diff --git a/workspaces/scorecard/.changeset/unify-metric-ids-camel-case.md b/workspaces/scorecard/.changeset/unify-metric-ids-camel-case.md new file mode 100644 index 0000000000..8980e3acc8 --- /dev/null +++ b/workspaces/scorecard/.changeset/unify-metric-ids-camel-case.md @@ -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`. diff --git a/workspaces/scorecard/app-config.local.EXAMPLE.yaml b/workspaces/scorecard/app-config.local.EXAMPLE.yaml index 0d8b54811f..a9b9b326c2 100644 --- a/workspaces/scorecard/app-config.local.EXAMPLE.yaml +++ b/workspaces/scorecard/app-config.local.EXAMPLE.yaml @@ -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 @@ -78,7 +78,7 @@ scorecard: color: '#be1ec7' # purple plugins: jira: - open_issues: + openIssues: schedule: frequency: { days: 1 } timeout: { minutes: 2 } @@ -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: diff --git a/workspaces/scorecard/app-config.production.yaml b/workspaces/scorecard/app-config.production.yaml index 64561d0cb5..816951fdc9 100644 --- a/workspaces/scorecard/app-config.production.yaml +++ b/workspaces/scorecard/app-config.production.yaml @@ -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 } diff --git a/workspaces/scorecard/app-config.yaml b/workspaces/scorecard/app-config.yaml index bb58c6d9f7..f3b5e465cf 100644 --- a/workspaces/scorecard/app-config.yaml +++ b/workspaces/scorecard/app-config.yaml @@ -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 @@ -269,7 +269,7 @@ 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 @@ -277,13 +277,13 @@ scorecard: 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 } diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts index 7fd1f007ba..3ef9cffccd 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts @@ -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', @@ -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; diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/routes.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/routes.ts index 2f516f5542..d51e9266b2 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/routes.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/constants/routes.ts @@ -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; diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardDrillDownPage.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardDrillDownPage.ts index 76a64e4ed3..da3f24c306 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardDrillDownPage.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardDrillDownPage.ts @@ -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; diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardPage.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardPage.ts index 923f969111..e990711a3f 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardPage.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/pages/ScorecardPage.ts @@ -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, }, ]; } diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts index 0539acdd02..e3df7e5b70 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts @@ -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) { @@ -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 = { - [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)) { @@ -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( @@ -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( @@ -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, ); }); @@ -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, ); }); @@ -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, ); }); @@ -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, ); }); @@ -959,7 +959,7 @@ test.describe('Scorecard Plugin Tests', () => { await mockScorecardEntitiesDrillDownWithSort( page, jiraEntitiesDrillDownResponse, - 'jira.open_issues', + 'jira.openIssues', ); await setupHomepageAggregationCard(page, homePage, { @@ -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, @@ -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(); }); @@ -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', ); }); }); diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts index 78fc1e1edf..edb6b8f008 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts @@ -197,7 +197,7 @@ export async function mockMetricsApi( /** * Mocks Jira drill-down "missing permission" scenario: metrics API 200, aggregations 403, entities 403. - * Use with direct navigation to /scorecard/aggregations/jira.open_issues/metrics/jira.open_issues + * Use with direct navigation to /scorecard/aggregations/jira.openIssues/metrics/jira.openIssues */ export async function mockJiraDrillDownMissingPermission( page: Page, @@ -209,22 +209,19 @@ export async function mockJiraDrillDownMissingPermission( status: 403, contentType: 'application/json', body: notAllowedError403Body( - '/metrics/jira.open_issues/catalog/aggregations', + '/metrics/jira.openIssues/catalog/aggregations', + ), + }); + }); + await page.route(entitiesDrillDownPattern('jira.openIssues'), async route => { + await route.fulfill({ + status: 403, + contentType: 'application/json', + body: notAllowedError403Body( + '/metrics/jira.openIssues/catalog/aggregations/entities?page=1&pageSize=5', ), }); }); - await page.route( - entitiesDrillDownPattern('jira.open_issues'), - async route => { - await route.fulfill({ - status: 403, - contentType: 'application/json', - body: notAllowedError403Body( - '/metrics/jira.open_issues/catalog/aggregations/entities?page=1&pageSize=5', - ), - }); - }, - ); } /** @@ -234,7 +231,7 @@ export async function mockJiraDrillDownMissingPermission( export async function mockScorecardEntitiesDrillDown( page: Page, responseData: object, - metricId: 'github.open_prs' | 'jira.open_issues' = 'github.open_prs', + metricId: 'github.openPrs' | 'jira.openIssues' = 'github.openPrs', status = 200, ) { await page.route(entitiesDrillDownPattern(metricId), async route => { @@ -280,7 +277,7 @@ function sortEntitiesByStatus( export async function mockScorecardEntitiesDrillDownWithSort( page: Page, responseData: object, - metricId: 'github.open_prs' | 'jira.open_issues' = 'github.open_prs', + metricId: 'github.openPrs' | 'jira.openIssues' = 'github.openPrs', status = 200, ) { await page.route(entitiesDrillDownPattern(metricId), async route => { diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts index ab7a6eb051..c75e20643c 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts @@ -41,10 +41,10 @@ function aggregationMetadataForRequestUrl(url: string): object { if (url.includes('openPrsWeightedKpi')) { return openPrsWeightedKpiMetadataResponse; } - if (url.includes('jira.open_issues')) { + if (url.includes('jira.openIssues')) { return jiraAggregatedResponse.metadata; } - if (url.includes('github.open_prs')) { + if (url.includes('github.openPrs')) { return githubAggregatedResponse.metadata; } return openPrsKpiMetadataResponse; diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/scorecardResponseUtils.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/scorecardResponseUtils.ts index 8dac563eca..af6320becc 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/scorecardResponseUtils.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/scorecardResponseUtils.ts @@ -26,7 +26,7 @@ const DEFAULT_NUMBER_THRESHOLDS = { export const customScorecardResponse = [ { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -52,7 +52,7 @@ export const customScorecardResponse = [ }, }, { - id: 'jira.open_issues', + id: 'jira.openIssues', status: 'success', metadata: { title: 'Jira open blocking tickets', @@ -82,7 +82,7 @@ export const customScorecardResponse = [ export const emptyScorecardResponse = []; const jiraOpenIssues = { - id: 'jira.open_issues', + id: 'jira.openIssues', status: 'success', metadata: { title: 'Jira open blocking tickets', @@ -120,7 +120,7 @@ const jiraOpenIssues = { export const unavailableMetricResponse = [ jiraOpenIssues, { - id: 'github.open_prs', + id: 'github.openPrs', status: 'error', metadata: { title: 'GitHub open PRs', @@ -160,7 +160,7 @@ export const unavailableMetricResponse = [ export const invalidThresholdResponse = [ jiraOpenIssues, { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -175,7 +175,7 @@ export const invalidThresholdResponse = [ thresholdResult: { status: 'error', error: - "ThresholdConfigFormatError: Invalid threshold annotation 'scorecard.io/github.open_prs.thresholds.rules.warning: 10--15' in entity 'component:default/all-scorecards-service': Invalid threshold expression: \"10--15\".", + "ThresholdConfigFormatError: Invalid threshold annotation 'scorecard.io/github.openPrs.thresholds.rules.warning: 10--15' in entity 'component:default/all-scorecards-service': Invalid threshold expression: \"10--15\".", }, }, }, @@ -219,7 +219,7 @@ export const openPrsWeightedKpiMetadataResponse = { * Colors align with aggregation KPI `options.thresholds` warning band (30–79%) in app-config. */ export const openPrsWeightedAggregatedResponse = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success' as const, metadata: { ...openPrsWeightedKpiMetadataResponse, @@ -265,7 +265,7 @@ export const gitHubWeightedPartiallyAggregatedResponse = { }; export const emptyOpenPrsWeightedAggregatedResponse = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success' as const, metadata: { ...openPrsWeightedKpiMetadataResponse, @@ -288,7 +288,7 @@ export const emptyOpenPrsWeightedAggregatedResponse = { /** Deliberately unknown `aggregationType` for UnsupportedAggregationType UI tests. */ export const openPrsWeightedUnsupportedAggregationResponse = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success' as const, metadata: { ...openPrsWeightedKpiMetadataResponse, @@ -298,11 +298,11 @@ export const openPrsWeightedUnsupportedAggregationResponse = { }; // Aggregated scorecard mocks: 10 GitHub entities, 10 Jira entities (totals in `result`) -/** Response for GET /api/scorecard/metrics?metricIds=jira.open_issues (metric metadata only). */ +/** Response for GET /api/scorecard/metrics?metricIds=jira.openIssues (metric metadata only). */ export const jiraMetricMetadataResponse = { metrics: [ { - id: 'jira.open_issues', + id: 'jira.openIssues', title: 'Jira open blocking tickets', description: 'Highlights the number of issues that are currently open in Jira.', @@ -359,7 +359,7 @@ const issueRules = [ export const sonarqubeScorecardResponse = [ { - id: 'sonarqube.quality_gate', + id: 'sonarqube.qualityGate', status: 'success', metadata: { title: 'SonarQube Quality Gate Status', @@ -383,7 +383,7 @@ export const sonarqubeScorecardResponse = [ }, }, sonarqubeNumberMetric( - 'sonarqube.open_issues', + 'sonarqube.openIssues', 'SonarQube Open Issues', 'Count of open issues (OPEN, CONFIRMED, REOPENED) in SonarQube.', 3, @@ -395,7 +395,7 @@ export const sonarqubeScorecardResponse = [ 'warning', ), sonarqubeNumberMetric( - 'sonarqube.security_rating', + 'sonarqube.securityRating', 'SonarQube Security Rating', 'SonarQube security rating.', 1, @@ -403,7 +403,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.security_issues', + 'sonarqube.securityIssues', 'SonarQube Security Issues', 'Count of open security vulnerabilities in SonarQube.', 0, @@ -411,7 +411,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.security_review_rating', + 'sonarqube.securityReviewRating', 'SonarQube Security Review Rating', 'SonarQube security review rating.', 1, @@ -419,7 +419,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.security_hotspots', + 'sonarqube.securityHotspots', 'SonarQube Security Hotspots', 'Count of security hotspots to review in SonarQube.', 2, @@ -427,7 +427,7 @@ export const sonarqubeScorecardResponse = [ 'warning', ), sonarqubeNumberMetric( - 'sonarqube.reliability_rating', + 'sonarqube.reliabilityRating', 'SonarQube Reliability Rating', 'SonarQube reliability rating.', 1, @@ -435,7 +435,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.reliability_issues', + 'sonarqube.reliabilityIssues', 'SonarQube Reliability Issues', 'Count of open bugs in SonarQube.', 0, @@ -443,7 +443,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.maintainability_rating', + 'sonarqube.maintainabilityRating', 'SonarQube Maintainability Rating', 'SonarQube maintainability rating.', 1, @@ -451,7 +451,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.maintainability_issues', + 'sonarqube.maintainabilityIssues', 'SonarQube Maintainability Issues', 'Count of open code smells in SonarQube.', 12, @@ -463,7 +463,7 @@ export const sonarqubeScorecardResponse = [ 'warning', ), sonarqubeNumberMetric( - 'sonarqube.code_coverage', + 'sonarqube.codeCoverage', 'SonarQube Code Coverage', 'Overall code coverage percentage in SonarQube.', 82.5, @@ -475,7 +475,7 @@ export const sonarqubeScorecardResponse = [ 'success', ), sonarqubeNumberMetric( - 'sonarqube.code_duplications', + 'sonarqube.codeDuplications', 'SonarQube Code Duplications', 'Percentage of duplicated lines in SonarQube.', 3.2, @@ -511,7 +511,7 @@ export const sonarqubeFailedQualityGateResponse = [ // Aggregated scorecard mocks: 10 GitHub entities, 10 Jira entities (totals in `result`) export const githubAggregatedResponse = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -572,7 +572,7 @@ export const gitHubPartiallyAggregatedResponse = { }; export const jiraAggregatedResponse = { - id: 'jira.open_issues', + id: 'jira.openIssues', status: 'success', metadata: { title: 'Jira open blocking tickets', @@ -597,7 +597,7 @@ export const jiraAggregatedResponse = { }; export const emptyJiraAggregatedResponse = { - id: 'jira.open_issues', + id: 'jira.openIssues', status: 'success', metadata: { title: 'Jira open blocking tickets', @@ -622,7 +622,7 @@ export const emptyJiraAggregatedResponse = { }; export const emptyGithubAggregatedResponse = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -646,9 +646,9 @@ export const emptyGithubAggregatedResponse = { }, }; -/** Mock response for GET .../api/scorecard/metrics/github.open_prs/catalog/aggregations/entities (10 entities, in sync with githubAggregatedResponse) */ +/** Mock response for GET .../api/scorecard/metrics/github.openPrs/catalog/aggregations/entities (10 entities, in sync with githubAggregatedResponse) */ export const githubEntitiesDrillDownResponse = { - metricId: 'github.open_prs', + metricId: 'github.openPrs', metricMetadata: { title: 'GitHub open PRs', description: @@ -771,9 +771,9 @@ export const githubEntitiesDrillDownResponse = { }, }; -/** Mock response for GET .../api/scorecard/metrics/jira.open_issues/catalog/aggregations/entities (in sync with jiraAggregatedResponse) */ +/** Mock response for GET .../api/scorecard/metrics/jira.openIssues/catalog/aggregations/entities (in sync with jiraAggregatedResponse) */ export const jiraEntitiesDrillDownResponse = { - metricId: 'jira.open_issues', + metricId: 'jira.openIssues', metricMetadata: { title: 'Jira open blocking tickets', description: @@ -838,7 +838,7 @@ export const jiraEntitiesDrillDownResponse = { /** Mock response for Jira entities drill-down when aggregation has no data (empty list). */ export const jiraEntitiesDrillDownNoDataResponse = { - metricId: 'jira.open_issues', + metricId: 'jira.openIssues', metricMetadata: { title: 'Jira open blocking tickets', description: diff --git a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/translationUtils.ts b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/translationUtils.ts index fb994bcc37..971b4d49f0 100644 --- a/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/translationUtils.ts +++ b/workspaces/scorecard/packages/app-legacy/e2e-tests/utils/translationUtils.ts @@ -27,14 +27,14 @@ export type ScorecardMessages = typeof scorecardMessages; /** English (ref) metric title – matches API metadata.title used when i18n falls back. */ export function getMetricTitleEn( - metricId: 'jira.open_issues' | 'github.open_prs', + metricId: 'jira.openIssues' | 'github.openPrs', ): string { return scorecardMessages.metric[metricId].title; } function transform(messages: typeof scorecardTranslationDe.messages) { const result = Object.keys(messages).reduce((res, key) => { - // metric.github.open_prs.title -> metric['github.open_prs'].title + // metric.github.openPrs.title -> metric['github.openPrs'].title // metric.openPrsKpi.title -> metric['openPrsKpi'].title (KPI / aggregation id) if (key.startsWith('metric.')) { const parts = key.split('.'); @@ -358,7 +358,7 @@ export function getHomepageEntityCalculationHealthText( /** Snapshot for the scorecard card on the drill-down page when permission is missing (no entity count in UI). */ export function getDrillDownMissingPermissionSnapshot( translations: ScorecardMessages, - metricId: 'jira.open_issues' | 'github.open_prs', + metricId: 'jira.openIssues' | 'github.openPrs', ) { return ` - article: @@ -373,7 +373,7 @@ export function getDrillDownMissingPermissionSnapshot( /** Snapshot for the scorecard card on the drill-down page when there is no data (no entity count in UI). */ export function getDrillDownNoDataFoundSnapshot( translations: ScorecardMessages, - metricId: 'jira.open_issues' | 'github.open_prs', + metricId: 'jira.openIssues' | 'github.openPrs', ) { return ` - article: @@ -412,7 +412,7 @@ function getHomepageDrillDownLinkSnapshot( export function getStatusGroupedCardSnapshot( translations: ScorecardMessages, options: { - drillDownMetricId: 'jira.open_issues' | 'github.open_prs'; + drillDownMetricId: 'jira.openIssues' | 'github.openPrs'; drillDownAggregationId?: string; /** Interpolation for homepage subheader (mock data uses 10/10). */ homepageCalculationHealth?: { healthy: string; total: string }; @@ -455,7 +455,7 @@ export function getStatusGroupedCardSnapshot( export function getAverageCardSnapshot( translations: ScorecardMessages, options: { - drillDownMetricId: 'jira.open_issues' | 'github.open_prs'; + drillDownMetricId: 'jira.openIssues' | 'github.openPrs'; drillDownAggregationId?: string; homepageCalculationHealth?: { healthy: string; total: string }; cardTitle: string; @@ -495,7 +495,7 @@ export function getAverageCardSnapshot( /** Snapshot for the scorecard card on the drill-down page (same as statusGrouped but without the entities link). */ export function getDrillDownCardSnapshot( translations: ScorecardMessages, - metricId: 'jira.open_issues' | 'github.open_prs', + metricId: 'jira.openIssues' | 'github.openPrs', options?: { title?: string; description?: string; diff --git a/workspaces/scorecard/packages/app-legacy/src/App.tsx b/workspaces/scorecard/packages/app-legacy/src/App.tsx index 0374d31e4d..3ea0976693 100644 --- a/workspaces/scorecard/packages/app-legacy/src/App.tsx +++ b/workspaces/scorecard/packages/app-legacy/src/App.tsx @@ -117,7 +117,7 @@ const mountPoints: HomePageCardMountPoint[] = [ }, props: { // The "metricId" represent deprecated logic and will be removed in the future - metricId: 'jira.open_issues', + metricId: 'jira.openIssues', }, }, }, @@ -149,7 +149,7 @@ const mountPoints: HomePageCardMountPoint[] = [ xxs: { w: 4, h: 6 }, }, props: { - aggregationId: 'github.open_prs', + aggregationId: 'github.openPrs', }, }, }, @@ -342,10 +342,10 @@ const mountPoints: HomePageCardMountPoint[] = [ metricId: { title: 'Metric (Needs currently a page reload after change!)', type: 'string', - default: 'jira.open_issues', + default: 'jira.openIssues', enum: [ - 'jira.open_issues', - 'github.open_prs', + 'jira.openIssues', + 'github.openPrs', 'filecheck.license', 'filecheck.codeowners', ], diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotConfig.ts b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotConfig.ts index 569b0ad8c7..04b2a00563 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotConfig.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotConfig.ts @@ -49,25 +49,25 @@ export const DEPENDABOT_SEVERITY_METRIC: Record< { id: string; title: string; description: string } > = { critical: { - id: 'dependabot.alerts_critical', + id: 'dependabot.alertsCritical', title: 'Dependabot Critical Alerts', description: 'Current count of open critical Dependabot alerts for a given repository.', }, high: { - id: 'dependabot.alerts_high', + id: 'dependabot.alertsHigh', title: 'Dependabot High Alerts', description: 'Current count of open high-severity Dependabot alerts for a given repository.', }, medium: { - id: 'dependabot.alerts_medium', + id: 'dependabot.alertsMedium', title: 'Dependabot Medium Alerts', description: 'Current count of open medium-severity Dependabot alerts for a given repository.', }, low: { - id: 'dependabot.alerts_low', + id: 'dependabot.alertsLow', title: 'Dependabot Low Alerts', description: 'Current count of open low-severity Dependabot alerts for a given repository.', diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProvider.test.ts index 98cebb3343..9ee4b1bcdc 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProvider.test.ts @@ -71,10 +71,10 @@ describe('DependabotMetricProvider', () => { describe('getProviderId / getMetric', () => { it.each([ - ['critical', 'dependabot.alerts_critical', 'Dependabot Critical Alerts'], - ['high', 'dependabot.alerts_high', 'Dependabot High Alerts'], - ['medium', 'dependabot.alerts_medium', 'Dependabot Medium Alerts'], - ['low', 'dependabot.alerts_low', 'Dependabot Low Alerts'], + ['critical', 'dependabot.alertsCritical', 'Dependabot Critical Alerts'], + ['high', 'dependabot.alertsHigh', 'Dependabot High Alerts'], + ['medium', 'dependabot.alertsMedium', 'Dependabot Medium Alerts'], + ['low', 'dependabot.alertsLow', 'Dependabot Low Alerts'], ] as const)( 'for %s returns id %s and title %s', (severity, expectedId, expectedTitle) => { diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProviderFactory.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProviderFactory.test.ts index 40e3644b82..185a0bee22 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProviderFactory.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-dependabot/src/metricProviders/DependabotMetricProviderFactory.test.ts @@ -34,7 +34,7 @@ describe('createDependabotMetricProvider', () => { mockLogger, 'high', ); - expect(provider.getProviderId()).toBe('dependabot.alerts_high'); + expect(provider.getProviderId()).toBe('dependabot.alertsHigh'); expect(provider.getProviderDatasourceId()).toBe('dependabot'); expect(provider.getMetricType()).toBe('number'); expect(provider.getMetricThresholds()).toBe(DEPENDABOT_THRESHOLDS); @@ -46,10 +46,10 @@ describe('createDependabotMetricProviders', () => { const providers = createDependabotMetricProviders(mockConfig, mockLogger); expect(providers).toHaveLength(4); expect(providers.map(p => p.getProviderId())).toEqual([ - 'dependabot.alerts_critical', - 'dependabot.alerts_high', - 'dependabot.alerts_medium', - 'dependabot.alerts_low', + 'dependabot.alertsCritical', + 'dependabot.alertsHigh', + 'dependabot.alertsMedium', + 'dependabot.alertsLow', ]); }); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-github/README.md b/workspaces/scorecard/plugins/scorecard-backend-module-github/README.md index 9a657d6da1..51ffab5c04 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-github/README.md +++ b/workspaces/scorecard/plugins/scorecard-backend-module-github/README.md @@ -60,11 +60,11 @@ spec: ## Available Metrics -### GitHub open PRs (`github.open_prs`) +### GitHub open PRs (`github.openPrs`) This metric counts all pull requests that are currently in an "open" state for the repository specified in the entity's `github.com/project-slug` annotation. -- **Metric ID**: `github.open_prs` +- **Metric ID**: `github.openPrs` - **Type**: Number - **Datasource**: `github` - **Default thresholds**: @@ -74,7 +74,7 @@ This metric counts all pull requests that are currently in an "open" state for t scorecard: plugins: github: - open_prs: + openPrs: thresholds: rules: - key: error @@ -99,7 +99,7 @@ The Scorecard plugin uses Backstage's built-in scheduler service to automaticall scorecard: plugins: github: - open_prs: + openPrs: schedule: frequency: cron: '0 6 * * *' diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-github/config.d.ts b/workspaces/scorecard/plugins/scorecard-backend-module-github/config.d.ts index 2bd3152e22..dbf9dc4580 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-github/config.d.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-github/config.d.ts @@ -22,7 +22,7 @@ export interface Config { plugins?: { /** Github datasource configuration */ github?: { - open_prs?: { + openPrs?: { thresholds?: { rules?: Array<{ key: 'error' | 'warning' | 'success'; diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-github/src/metricProviders/GithubOpenPRsProvider.ts b/workspaces/scorecard/plugins/scorecard-backend-module-github/src/metricProviders/GithubOpenPRsProvider.ts index 1263392fac..13e9fdbee1 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-github/src/metricProviders/GithubOpenPRsProvider.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-github/src/metricProviders/GithubOpenPRsProvider.ts @@ -38,7 +38,7 @@ export class GithubOpenPRsProvider implements MetricProvider<'number'> { } getProviderId() { - return 'github.open_prs'; + return 'github.openPrs'; } getMetricType(): 'number' { diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/README.md b/workspaces/scorecard/plugins/scorecard-backend-module-jira/README.md index a93de749da..b46b1568e9 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/README.md +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/README.md @@ -90,7 +90,7 @@ Options define configuration that affect fetch jira issues global configuration, scorecard: plugins: jira: - open_issues: + openIssues: options: # Optional: use mandatoryFilter filter if need to replaces default which is "type = Bug AND resolution = Unresolved" mandatoryFilter: Type = Task AND Resolution = Resolved @@ -106,7 +106,7 @@ The Scorecard plugin uses Backstage's built-in scheduler service to automaticall scorecard: plugins: jira: - open_issues: + openIssues: schedule: frequency: cron: '0 6 * * *' @@ -180,11 +180,11 @@ spec: ## Available Metrics -### Jira Issues (`jira.open_issues`) +### Jira Issues (`jira.openIssues`) This metric counts all jira issues that match the filter condition specified in annotation and app-config.yaml -- **Metric ID**: `jira.open_issues` +- **Metric ID**: `jira.openIssues` - **Type**: `Number` - **Datasource**: `jira` - **Default thresholds**: @@ -194,7 +194,7 @@ This metric counts all jira issues that match the filter condition specified in scorecard: plugins: jira: - open_issues: + openIssues: thresholds: rules: - key: success diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/__fixtures__/testUtils.ts b/workspaces/scorecard/plugins/scorecard-backend-module-jira/__fixtures__/testUtils.ts index 4f9c29db47..4d89f96544 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/__fixtures__/testUtils.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/__fixtures__/testUtils.ts @@ -78,7 +78,7 @@ export function newMockRootConfig({ scorecard: { plugins: { jira: { - open_issues: { + openIssues: { options, thresholds, }, diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/config.d.ts b/workspaces/scorecard/plugins/scorecard-backend-module-jira/config.d.ts index 9f36f53558..8f6f4c3e4d 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/config.d.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/config.d.ts @@ -38,7 +38,7 @@ export interface Config { plugins?: { /** JIRA datasource configuration */ jira?: { - open_issues?: { + openIssues?: { options?: { mandatoryFilter?: string; customFilter?: string; diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/constants/jiraOpenIssues.ts b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/constants/jiraOpenIssues.ts index fcae738fcf..d75e231ad5 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/constants/jiraOpenIssues.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/constants/jiraOpenIssues.ts @@ -15,7 +15,7 @@ */ export const OPEN_ISSUES_CONFIG_PATH = - 'scorecard.plugins.jira.open_issues' as const; + 'scorecard.plugins.jira.openIssues' as const; /** * Jira integration configuration path diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.test.ts index 792f8dd4af..5ae2089d01 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.test.ts @@ -84,12 +84,12 @@ describe('JiraOpenIssuesProvider', () => { }); describe('getProviderId', () => { - it('should return "jira.open_issues"', () => { + it('should return "jira.openIssues"', () => { const provider = JiraOpenIssuesProvider.fromConfig( mockConfig, mockAuthOptions, ); - expect(provider.getProviderId()).toEqual('jira.open_issues'); + expect(provider.getProviderId()).toEqual('jira.openIssues'); }); }); @@ -119,7 +119,7 @@ describe('JiraOpenIssuesProvider', () => { it('should return correct metric metadata', () => { expect(getMetricResult).toEqual({ - id: 'jira.open_issues', + id: 'jira.openIssues', title: 'Jira open blocking tickets', description: 'Highlights the number of issues that are currently open in Jira.', diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.ts b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.ts index 6cdbbbc786..8aac4f6939 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-jira/src/metricProviders/JiraOpenIssuesProvider.ts @@ -62,7 +62,7 @@ export class JiraOpenIssuesProvider implements MetricProvider<'number'> { } getProviderId() { - return 'jira.open_issues'; + return 'jira.openIssues'; } getMetricType(): 'number' { diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/README.md b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/README.md index cb72ade046..136d379fe5 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/README.md +++ b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/README.md @@ -50,26 +50,26 @@ All OpenSSF metrics use default thresholds: **Error** <2, **Warning** 2–7, 18 metrics from [OpenSSF checks](https://github.com/ossf/scorecard/blob/main/docs/checks.md): -| Metric | Description | -| -------------------------------- | ------------------------------------------------------------------------------------------- | -| `openssf.binary_artifacts` | No executable (binary) artifacts in the source repository. | -| `openssf.branch_protection` | Default and release branches protected (e.g. require review, status checks, no force push). | -| `openssf.cii_best_practices` | Project has an OpenSSF Best Practices badge (passing, silver, or gold). | -| `openssf.ci_tests` | Tests run before pull requests are merged. | -| `openssf.code_review` | Human code review required before PRs are merged. | -| `openssf.contributors` | Recent contributors from multiple organizations. | -| `openssf.dangerous_workflow` | GitHub Actions workflows avoid dangerous patterns (untrusted checkout, script injection). | -| `openssf.dependency_update_tool` | Dependency update tool in use (e.g. Dependabot, Renovate). | -| `openssf.fuzzing` | Fuzzing in use (e.g. OSS-Fuzz, ClusterFuzzLite, or language fuzz tests). | -| `openssf.license` | Project has a published license. | -| `openssf.maintained` | Project is actively maintained (not archived, recent activity). | -| `openssf.packaging` | Project is published as a package. | -| `openssf.pinned_dependencies` | Dependencies pinned (hash or fixed version) in build/release. | -| `openssf.sast` | Static application security testing (SAST) in use. | -| `openssf.security_policy` | Security policy present (e.g. SECURITY.md). | -| `openssf.signed_releases` | Releases are cryptographically signed. | -| `openssf.token_permissions` | GitHub Actions use minimal token permissions. | -| `openssf.vulnerabilities` | Known vulnerabilities in dependencies (lower score = more issues). | +| Metric | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------- | +| `openssf.binaryArtifacts` | No executable (binary) artifacts in the source repository. | +| `openssf.branchProtection` | Default and release branches protected (e.g. require review, status checks, no force push). | +| `openssf.ciiBestPractices` | Project has an OpenSSF Best Practices badge (passing, silver, or gold). | +| `openssf.ciTests` | Tests run before pull requests are merged. | +| `openssf.codeReview` | Human code review required before PRs are merged. | +| `openssf.contributors` | Recent contributors from multiple organizations. | +| `openssf.dangerousWorkflow` | GitHub Actions workflows avoid dangerous patterns (untrusted checkout, script injection). | +| `openssf.dependencyUpdateTool` | Dependency update tool in use (e.g. Dependabot, Renovate). | +| `openssf.fuzzing` | Fuzzing in use (e.g. OSS-Fuzz, ClusterFuzzLite, or language fuzz tests). | +| `openssf.license` | Project has a published license. | +| `openssf.maintained` | Project is actively maintained (not archived, recent activity). | +| `openssf.packaging` | Project is published as a package. | +| `openssf.pinnedDependencies` | Dependencies pinned (hash or fixed version) in build/release. | +| `openssf.sast` | Static application security testing (SAST) in use. | +| `openssf.securityPolicy` | Security policy present (e.g. SECURITY.md). | +| `openssf.signedReleases` | Releases are cryptographically signed. | +| `openssf.tokenPermissions` | GitHub Actions use minimal token permissions. | +| `openssf.vulnerabilities` | Known vulnerabilities in dependencies (lower score = more issues). | ## Troubleshooting diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.test.ts index 0e67fabb46..83967783b8 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.test.ts @@ -77,7 +77,7 @@ describe('OpenSSFMetricProvider', () => { it('normalizes hyphenated check names for provider id', () => { const provider = new OpenSSFMetricProvider(hyphenatedCheckConfig); - expect(provider.getProviderId()).toBe('openssf.code_review'); + expect(provider.getProviderId()).toBe('openssf.codeReview'); }); it('returns openssf as provider datasource id', () => { @@ -228,7 +228,9 @@ describe('OpenSSFMetricProvider', () => { const providerIds = providers.map(provider => provider.getProviderId()); const expectedProviderIds = OPENSSF_METRICS.map(metric => { - const normalizedName = metric.name.toLowerCase().replace(/-/g, '_'); + const normalizedName = metric.name + .replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase()) + .replace(/^[A-Z]/, c => c.toLowerCase()); return `openssf.${normalizedName}`; }); diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.ts b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.ts index b60d016acc..260b1614c8 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-openssf/src/metricProviders/OpenSSFMetricProvider.ts @@ -56,8 +56,8 @@ export class OpenSSFMetricProvider implements MetricProvider<'number'> { getProviderId(): string { const normalizedName = this.getMetricName() - .toLowerCase() - .replace(/-/g, '_'); + .replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase()) + .replace(/^[A-Z]/, c => c.toLowerCase()); return `openssf.${normalizedName}`; } diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/README.md b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/README.md index 618c97587f..154ca3ecf9 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/README.md +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/README.md @@ -4,20 +4,20 @@ Adds SonarQube / SonarCloud metrics to the scorecard plugin. ## Metrics -| Metric ID | Type | Description | -| ---------------------------------- | ------- | ------------------------------------------------ | -| `sonarqube.quality_gate` | boolean | Whether the project passes its quality gate | -| `sonarqube.open_issues` | number | Count of open issues (OPEN, CONFIRMED, REOPENED) | -| `sonarqube.security_rating` | number | Security rating | -| `sonarqube.security_issues` | number | Count of open security vulnerabilities | -| `sonarqube.security_review_rating` | number | Security review rating | -| `sonarqube.security_hotspots` | number | Count of security hotspots to review | -| `sonarqube.reliability_rating` | number | Reliability rating | -| `sonarqube.reliability_issues` | number | Count of open bugs | -| `sonarqube.maintainability_rating` | number | Maintainability rating | -| `sonarqube.maintainability_issues` | number | Count of open code smells | -| `sonarqube.code_coverage` | number | Overall code coverage percentage | -| `sonarqube.code_duplications` | number | Percentage of duplicated lines | +| Metric ID | Type | Description | +| --------------------------------- | ------- | ------------------------------------------------ | +| `sonarqube.qualityGate` | boolean | Whether the project passes its quality gate | +| `sonarqube.openIssues` | number | Count of open issues (OPEN, CONFIRMED, REOPENED) | +| `sonarqube.securityRating` | number | Security rating | +| `sonarqube.securityIssues` | number | Count of open security vulnerabilities | +| `sonarqube.securityReviewRating` | number | Security review rating | +| `sonarqube.securityHotspots` | number | Count of security hotspots to review | +| `sonarqube.reliabilityRating` | number | Reliability rating | +| `sonarqube.reliabilityIssues` | number | Count of open bugs | +| `sonarqube.maintainabilityRating` | number | Maintainability rating | +| `sonarqube.maintainabilityIssues` | number | Count of open code smells | +| `sonarqube.codeCoverage` | number | Overall code coverage percentage | +| `sonarqube.codeDuplications` | number | Percentage of duplicated lines | ## Installation diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBasicMetricProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBasicMetricProvider.test.ts index 9d8d232a1b..fc031f5fa7 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBasicMetricProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBasicMetricProvider.test.ts @@ -38,7 +38,7 @@ const emptyThresholds: ThresholdConfig = { rules: [] }; class TestBooleanBasic extends SonarQubeBasicMetricProvider<'boolean'> { constructor( client: SonarQubeClient, - metricId: 'quality_gate', + metricId: 'qualityGate', thresholds: ThresholdConfig, ) { super(client, metricId, thresholds, 'boolean'); @@ -59,15 +59,15 @@ const providers = [ { provider: new TestBooleanBasic( makeClient(), - 'quality_gate', + 'qualityGate', emptyThresholds, ), - metricId: 'quality_gate', + metricId: 'qualityGate', type: 'boolean', }, { - provider: new TestNumberBasic(makeClient(), 'open_issues', emptyThresholds), - metricId: 'open_issues', + provider: new TestNumberBasic(makeClient(), 'openIssues', emptyThresholds), + metricId: 'openIssues', type: 'number', }, ]; diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBooleanMetricProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBooleanMetricProvider.test.ts index 29507a9690..b73d74cc3e 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBooleanMetricProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeBooleanMetricProvider.test.ts @@ -52,7 +52,7 @@ describe('SonarQubeBooleanMetricProvider', () => { const provider = SonarQubeBooleanMetricProvider.fromConfig( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); expect(provider.getMetricThresholds()).toBeDefined(); expect(provider.getMetricThresholds().rules).toHaveLength(2); @@ -65,7 +65,7 @@ describe('SonarQubeBooleanMetricProvider', () => { const provider = SonarQubeBooleanMetricProvider.fromConfig( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); const result = await provider.calculateMetric(entity()); @@ -82,7 +82,7 @@ describe('SonarQubeBooleanMetricProvider', () => { const provider = SonarQubeBooleanMetricProvider.fromConfig( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); const result = await provider.calculateMetric(entity()); @@ -95,7 +95,7 @@ describe('SonarQubeBooleanMetricProvider', () => { const provider = SonarQubeBooleanMetricProvider.fromConfig( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); await provider.calculateMetric(entity('internal/my-project')); @@ -110,7 +110,7 @@ describe('SonarQubeBooleanMetricProvider', () => { const provider = SonarQubeBooleanMetricProvider.fromConfig( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); const e = entity(); delete e.metadata.annotations!['sonarqube.org/project-key']; diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeConfig.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeConfig.ts index 1378faed90..0a6a6dadbb 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeConfig.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeConfig.ts @@ -51,39 +51,39 @@ export function parseProjectKeyAnnotation(entity: Entity): SonarQubeAnnotation { } export const SONARQUBE_METRICS = [ - 'quality_gate', - 'open_issues', - 'security_rating', - 'security_issues', - 'security_review_rating', - 'security_hotspots', - 'reliability_rating', - 'reliability_issues', - 'maintainability_rating', - 'maintainability_issues', - 'code_coverage', - 'code_duplications', + 'qualityGate', + 'openIssues', + 'securityRating', + 'securityIssues', + 'securityReviewRating', + 'securityHotspots', + 'reliabilityRating', + 'reliabilityIssues', + 'maintainabilityRating', + 'maintainabilityIssues', + 'codeCoverage', + 'codeDuplications', ] as const; export type SonarQubeMetricId = (typeof SONARQUBE_METRICS)[number]; -export const SONARQUBE_BOOLEAN_METRICS = ['quality_gate'] as const; +export const SONARQUBE_BOOLEAN_METRICS = ['qualityGate'] as const; export type SonarQubeBooleanMetricId = (typeof SONARQUBE_BOOLEAN_METRICS)[number]; export const SONARQUBE_NUMBER_METRICS = [ - 'open_issues', - 'security_rating', - 'security_issues', - 'security_review_rating', - 'security_hotspots', - 'reliability_rating', - 'reliability_issues', - 'maintainability_rating', - 'maintainability_issues', - 'code_coverage', - 'code_duplications', + 'openIssues', + 'securityRating', + 'securityIssues', + 'securityReviewRating', + 'securityHotspots', + 'reliabilityRating', + 'reliabilityIssues', + 'maintainabilityRating', + 'maintainabilityIssues', + 'codeCoverage', + 'codeDuplications', ] as const; export type SonarQubeNumberMetricId = (typeof SONARQUBE_NUMBER_METRICS)[number]; @@ -92,64 +92,64 @@ export const SONARQUBE_METRIC_CONFIG: Record< SonarQubeMetricId, { id: string; title: string; description: string } > = { - quality_gate: { - id: 'sonarqube.quality_gate', + qualityGate: { + id: 'sonarqube.qualityGate', title: 'SonarQube Quality Gate Status', description: 'Whether the project passes its SonarQube quality gate.', }, - open_issues: { - id: 'sonarqube.open_issues', + openIssues: { + id: 'sonarqube.openIssues', title: 'SonarQube Open Issues', description: 'Count of open issues (OPEN, CONFIRMED, REOPENED) in SonarQube.', }, - security_rating: { - id: 'sonarqube.security_rating', + securityRating: { + id: 'sonarqube.securityRating', title: 'SonarQube Security Rating', description: 'SonarQube security rating.', }, - security_issues: { - id: 'sonarqube.security_issues', + securityIssues: { + id: 'sonarqube.securityIssues', title: 'SonarQube Security Issues', description: 'Count of open security vulnerabilities in SonarQube.', }, - security_review_rating: { - id: 'sonarqube.security_review_rating', + securityReviewRating: { + id: 'sonarqube.securityReviewRating', title: 'SonarQube Security Review Rating', description: 'SonarQube security review rating.', }, - security_hotspots: { - id: 'sonarqube.security_hotspots', + securityHotspots: { + id: 'sonarqube.securityHotspots', title: 'SonarQube Security Hotspots', description: 'Count of security hotspots to review in SonarQube.', }, - reliability_rating: { - id: 'sonarqube.reliability_rating', + reliabilityRating: { + id: 'sonarqube.reliabilityRating', title: 'SonarQube Reliability Rating', description: 'SonarQube reliability rating.', }, - reliability_issues: { - id: 'sonarqube.reliability_issues', + reliabilityIssues: { + id: 'sonarqube.reliabilityIssues', title: 'SonarQube Reliability Issues', description: 'Count of open bugs in SonarQube.', }, - maintainability_rating: { - id: 'sonarqube.maintainability_rating', + maintainabilityRating: { + id: 'sonarqube.maintainabilityRating', title: 'SonarQube Maintainability Rating', description: 'SonarQube maintainability rating.', }, - maintainability_issues: { - id: 'sonarqube.maintainability_issues', + maintainabilityIssues: { + id: 'sonarqube.maintainabilityIssues', title: 'SonarQube Maintainability Issues', description: 'Count of open code smells in SonarQube.', }, - code_coverage: { - id: 'sonarqube.code_coverage', + codeCoverage: { + id: 'sonarqube.codeCoverage', title: 'SonarQube Code Coverage', description: 'Overall code coverage percentage in SonarQube.', }, - code_duplications: { - id: 'sonarqube.code_duplications', + codeDuplications: { + id: 'sonarqube.codeDuplications', title: 'SonarQube Code Duplications', description: 'Percentage of duplicated lines in SonarQube.', }, @@ -157,24 +157,24 @@ export const SONARQUBE_METRIC_CONFIG: Record< /** * Maps scorecard metric IDs to SonarQube API metric keys. - * `open_issues` uses a dedicated API endpoint, so it has no measures key. + * `openIssues` uses a dedicated API endpoint, so it has no measures key. */ export const SONARQUBE_API_METRIC_KEYS: Record< SonarQubeMetricId, { apiKey: string } | { useQualityGateApi: true } | { useOpenIssuesApi: true } > = { - quality_gate: { useQualityGateApi: true }, - open_issues: { useOpenIssuesApi: true }, - security_rating: { apiKey: 'security_rating' }, - security_issues: { apiKey: 'vulnerabilities' }, - security_review_rating: { apiKey: 'security_review_rating' }, - security_hotspots: { apiKey: 'security_hotspots' }, - reliability_rating: { apiKey: 'reliability_rating' }, - reliability_issues: { apiKey: 'bugs' }, - maintainability_rating: { apiKey: 'sqale_rating' }, - maintainability_issues: { apiKey: 'code_smells' }, - code_coverage: { apiKey: 'coverage' }, - code_duplications: { apiKey: 'duplicated_lines_density' }, + qualityGate: { useQualityGateApi: true }, + openIssues: { useOpenIssuesApi: true }, + securityRating: { apiKey: 'security_rating' }, + securityIssues: { apiKey: 'vulnerabilities' }, + securityReviewRating: { apiKey: 'security_review_rating' }, + securityHotspots: { apiKey: 'security_hotspots' }, + reliabilityRating: { apiKey: 'reliability_rating' }, + reliabilityIssues: { apiKey: 'bugs' }, + maintainabilityRating: { apiKey: 'sqale_rating' }, + maintainabilityIssues: { apiKey: 'code_smells' }, + codeCoverage: { apiKey: 'coverage' }, + codeDuplications: { apiKey: 'duplicated_lines_density' }, }; export const SONARQUBE_BOOLEAN_THRESHOLDS: ThresholdConfig = { @@ -223,53 +223,53 @@ export const SONARQUBE_NUMBER_THRESHOLDS: Record< SonarQubeNumberMetricId, ThresholdConfig > = { - open_issues: { + openIssues: { rules: [ { key: 'success', expression: '<1' }, { key: 'warning', expression: '1-10' }, { key: 'error', expression: '>10' }, ], }, - security_rating: RATING_THRESHOLDS, - security_review_rating: RATING_THRESHOLDS, - reliability_rating: RATING_THRESHOLDS, - maintainability_rating: RATING_THRESHOLDS, - security_issues: { + securityRating: RATING_THRESHOLDS, + securityReviewRating: RATING_THRESHOLDS, + reliabilityRating: RATING_THRESHOLDS, + maintainabilityRating: RATING_THRESHOLDS, + securityIssues: { rules: [ { key: 'success', expression: '<1' }, { key: 'warning', expression: '1-5' }, { key: 'error', expression: '>5' }, ], }, - security_hotspots: { + securityHotspots: { rules: [ { key: 'success', expression: '<1' }, { key: 'warning', expression: '1-5' }, { key: 'error', expression: '>5' }, ], }, - reliability_issues: { + reliabilityIssues: { rules: [ { key: 'success', expression: '<1' }, { key: 'warning', expression: '1-5' }, { key: 'error', expression: '>5' }, ], }, - maintainability_issues: { + maintainabilityIssues: { rules: [ { key: 'success', expression: '<10' }, { key: 'warning', expression: '10-50' }, { key: 'error', expression: '>50' }, ], }, - code_coverage: { + codeCoverage: { rules: [ { key: 'success', expression: '>80' }, { key: 'warning', expression: '50-80' }, { key: 'error', expression: '<50' }, ], }, - code_duplications: { + codeDuplications: { rules: [ { key: 'success', expression: '<3' }, { key: 'warning', expression: '3-10' }, diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.test.ts index 967a648355..ac6ee283af 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.test.ts @@ -24,44 +24,44 @@ const mockConfig = new ConfigReader({}); const mockLogger = mockServices.logger.mock(); describe('createMetricProvider', () => { - it('returns a boolean provider for quality_gate', () => { + it('returns a boolean provider for qualityGate', () => { const provider = SonarQubeMetricProviderFactory.createMetricProvider( mockConfig, mockLogger, - 'quality_gate', + 'qualityGate', ); - expect(provider.getProviderId()).toBe('sonarqube.quality_gate'); + expect(provider.getProviderId()).toBe('sonarqube.qualityGate'); expect(provider.getProviderDatasourceId()).toBe('sonarqube'); expect(provider.getMetricType()).toBe('boolean'); }); - it('returns a number provider for open_issues', () => { + it('returns a number provider for openIssues', () => { const provider = SonarQubeMetricProviderFactory.createMetricProvider( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); - expect(provider.getProviderId()).toBe('sonarqube.open_issues'); + expect(provider.getProviderId()).toBe('sonarqube.openIssues'); expect(provider.getMetricType()).toBe('number'); }); - it('returns a number provider for security_rating', () => { + it('returns a number provider for securityRating', () => { const provider = SonarQubeMetricProviderFactory.createMetricProvider( mockConfig, mockLogger, - 'security_rating', + 'securityRating', ); - expect(provider.getProviderId()).toBe('sonarqube.security_rating'); + expect(provider.getProviderId()).toBe('sonarqube.securityRating'); expect(provider.getMetricType()).toBe('number'); }); - it('returns a number provider for security_issues', () => { + it('returns a number provider for securityIssues', () => { const provider = SonarQubeMetricProviderFactory.createMetricProvider( mockConfig, mockLogger, - 'security_issues', + 'securityIssues', ); - expect(provider.getProviderId()).toBe('sonarqube.security_issues'); + expect(provider.getProviderId()).toBe('sonarqube.securityIssues'); expect(provider.getMetricType()).toBe('number'); }); }); @@ -74,18 +74,18 @@ describe('fromConfig', () => { ); expect(providers).toHaveLength(12); expect(providers.map(p => p.getProviderId())).toEqual([ - 'sonarqube.quality_gate', - 'sonarqube.open_issues', - 'sonarqube.security_rating', - 'sonarqube.security_issues', - 'sonarqube.security_review_rating', - 'sonarqube.security_hotspots', - 'sonarqube.reliability_rating', - 'sonarqube.reliability_issues', - 'sonarqube.maintainability_rating', - 'sonarqube.maintainability_issues', - 'sonarqube.code_coverage', - 'sonarqube.code_duplications', + 'sonarqube.qualityGate', + 'sonarqube.openIssues', + 'sonarqube.securityRating', + 'sonarqube.securityIssues', + 'sonarqube.securityReviewRating', + 'sonarqube.securityHotspots', + 'sonarqube.reliabilityRating', + 'sonarqube.reliabilityIssues', + 'sonarqube.maintainabilityRating', + 'sonarqube.maintainabilityIssues', + 'sonarqube.codeCoverage', + 'sonarqube.codeDuplications', ]); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.ts index 2440a98544..964cff740a 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeMetricProviderFactory.ts @@ -30,7 +30,7 @@ export class SonarQubeMetricProviderFactory { logger: LoggerService, metricId: SonarQubeMetricId, ): MetricProvider { - if (metricId === 'quality_gate') { + if (metricId === 'qualityGate') { return SonarQubeBooleanMetricProvider.fromConfig( config, logger, diff --git a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeNumberMetricProvider.test.ts b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeNumberMetricProvider.test.ts index a7d4a98209..4aaf24bdb4 100644 --- a/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeNumberMetricProvider.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend-module-sonarqube/src/metricProviders/SonarQubeNumberMetricProvider.test.ts @@ -54,7 +54,7 @@ describe('SonarQubeNumberMetricProvider', () => { const provider = SonarQubeNumberMetricProvider.fromConfig( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); expect(provider.getMetricThresholds()).toBeDefined(); expect(provider.getMetricThresholds().rules).toBeDefined(); @@ -62,12 +62,12 @@ describe('SonarQubeNumberMetricProvider', () => { }); describe('calculateMetric', () => { - it('should call getOpenIssuesCount for open_issues metric', async () => { + it('should call getOpenIssuesCount for openIssues metric', async () => { mockGetOpenIssuesCount.mockResolvedValue(42); const provider = SonarQubeNumberMetricProvider.fromConfig( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); const result = await provider.calculateMetric(entity()); @@ -81,16 +81,16 @@ describe('SonarQubeNumberMetricProvider', () => { }); it.each([ - ['security_rating', 'security_rating', 2], - ['security_issues', 'vulnerabilities', 7], - ['security_review_rating', 'security_review_rating', 1], - ['security_hotspots', 'security_hotspots', 3], - ['reliability_rating', 'reliability_rating', 1], - ['reliability_issues', 'bugs', 12], - ['maintainability_rating', 'sqale_rating', 2], - ['maintainability_issues', 'code_smells', 45], - ['code_coverage', 'coverage', 82.5], - ['code_duplications', 'duplicated_lines_density', 3.2], + ['securityRating', 'security_rating', 2], + ['securityIssues', 'vulnerabilities', 7], + ['securityReviewRating', 'security_review_rating', 1], + ['securityHotspots', 'security_hotspots', 3], + ['reliabilityRating', 'reliability_rating', 1], + ['reliabilityIssues', 'bugs', 12], + ['maintainabilityRating', 'sqale_rating', 2], + ['maintainabilityIssues', 'code_smells', 45], + ['codeCoverage', 'coverage', 82.5], + ['codeDuplications', 'duplicated_lines_density', 3.2], ] as const)( 'should call getMeasures with %s API key for %s metric', async (metricId, apiKey, value) => { @@ -118,7 +118,7 @@ describe('SonarQubeNumberMetricProvider', () => { const provider = SonarQubeNumberMetricProvider.fromConfig( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); await provider.calculateMetric(entity('internal/my-project')); @@ -133,7 +133,7 @@ describe('SonarQubeNumberMetricProvider', () => { const provider = SonarQubeNumberMetricProvider.fromConfig( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); const e = entity(); delete e.metadata.annotations!['sonarqube.org/project-key']; @@ -148,7 +148,7 @@ describe('SonarQubeNumberMetricProvider', () => { const provider = SonarQubeNumberMetricProvider.fromConfig( mockConfig, mockLogger, - 'open_issues', + 'openIssues', ); expect(await provider.calculateMetric(entity())).toBe(0); diff --git a/workspaces/scorecard/plugins/scorecard-backend/README.md b/workspaces/scorecard/plugins/scorecard-backend/README.md index a3c59e69c7..a176ba8ea5 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/README.md +++ b/workspaces/scorecard/plugins/scorecard-backend/README.md @@ -62,7 +62,7 @@ conditions: rule: HAS_METRIC_ID resourceType: scorecard-metric params: - metricIds: ['github.open_prs'] + metricIds: ['github.openPrs'] ``` This policy would allow users to read only the GitHub Open PRs metric, while restricting access to other available metrics. @@ -88,13 +88,13 @@ For more information about schedule configuration options, see the [Metric Colle The following metric providers are available: -| Provider | Metric ID | Title | Description | Type | -| -------------- | ------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------- | -| **GitHub** | `github.open_prs` | GitHub open PRs | Count of open Pull Requests in GitHub | number | -| **Filecheck** | `filecheck.*` | File Checks | Checks whether specific files (e.g., `README.md`, `LICENSE`, `CODEOWNERS`) exist in a repository. | boolean | -| **Jira** | `jira.open_issues` | Jira open issues | The number of opened issues in Jira | number | -| **OpenSSF** | `openssf.*` | OpenSSF Security Scorecards | 18 security metrics from OpenSSF Scorecards (e.g., `openssf.code_review`, `openssf.maintained`). Each returns a score from 0-10. | number | -| **Dependabot** | `dependabot.*` | Dependabot Alerts | Critical, High, Medium and Low CVE Alerts | number | +| Provider | Metric ID | Title | Description | Type | +| -------------- | ----------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- | +| **GitHub** | `github.openPrs` | GitHub open PRs | Count of open Pull Requests in GitHub | number | +| **Filecheck** | `filecheck.*` | File Checks | Checks whether specific files (e.g., `README.md`, `LICENSE`, `CODEOWNERS`) exist in a repository. | boolean | +| **Jira** | `jira.openIssues` | Jira open issues | The number of opened issues in Jira | number | +| **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 | +| **Dependabot** | `dependabot.*` | Dependabot Alerts | Critical, High, Medium and Low CVE Alerts | number | To use these providers, install the corresponding backend modules: @@ -131,17 +131,17 @@ scorecard: title: 'Jira open issues KPI' description: 'Open issues across entities you own, grouped by status.' type: statusGrouped - metricId: jira.open_issues + metricId: jira.openIssues openPrsKpi: title: 'GitHub open PRs KPI' description: 'Open pull requests grouped by status.' type: statusGrouped - metricId: github.open_prs + metricId: github.openPrs openPrsWeightedKpi: title: 'GitHub open PRs (weighted health)' description: 'Weighted health from status counts using configurable scores.' type: average - metricId: github.open_prs + metricId: github.openPrs options: statusScores: success: 100 @@ -170,7 +170,7 @@ scorecard: | `options` | Optional for `statusGrouped`. **Required** for `average`: must include **`options.statusScores`** — map status keys to numeric weights (typically one entry per **metric threshold rule key**). Optionally **`options.thresholds`** (same shape as metric thresholds; see [thresholds.md — Aggregation KPI result thresholds](./docs/thresholds.md#4-aggregation-kpi-result-thresholds-average-type)); evaluated on **`averageScore`** (**0–100** portfolio percentage, **one decimal**); first match sets **`aggregationChartDisplayColor`**. The API includes **`averageScore`**, **`averageWeightedSum`**, **`averageMaxPossible`**, and **`aggregationChartDisplayColor`** (from configured or default result thresholds). | - **Path**: `scorecard.aggregationKPIs.`. -- If **`aggregationKPIs` is omitted** or a given id is not listed, **`GET /aggregations/:aggregationId`** still works when **`aggregationId` equals the metric id** (e.g. `github.open_prs`): the backend uses that metric with the default `statusGrouped` aggregation and metric-defined title/description. +- If **`aggregationKPIs` is omitted** or a given id is not listed, **`GET /aggregations/:aggregationId`** still works when **`aggregationId` equals the metric id** (e.g. `github.openPrs`): the backend uses that metric with the default `statusGrouped` aggregation and metric-defined title/description. - **Startup validation**: the backend validates every **`scorecard.aggregationKPIs`** entry when the plugin loads. Invalid configuration (including **`average`** 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). **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). @@ -183,10 +183,10 @@ Returns a list of available metrics. Supports filtering by metric IDs or datasou #### Query Parameters -| Parameter | Type | Required | Description | -| ------------ | ------ | -------- | ------------------------------------------------------------------------------------------ | -| `metricIds` | string | No | Comma-separated list of metric IDs to filter by (e.g., `github.open_prs,jira.open_issues`) | -| `datasource` | string | No | Filter metrics by datasource ID (e.g., `github`, `jira`, `sonar`) | +| Parameter | Type | Required | Description | +| ------------ | ------ | -------- | ---------------------------------------------------------------------------------------- | +| `metricIds` | string | No | Comma-separated list of metric IDs to filter by (e.g., `github.openPrs,jira.openIssues`) | +| `datasource` | string | No | Filter metrics by datasource ID (e.g., `github`, `jira`, `sonar`) | #### Behavior @@ -203,7 +203,7 @@ curl -X GET "{{url}}/api/scorecard/metrics" \ -H "Authorization: Bearer " # Get specific metrics by IDs -curl -X GET "{{url}}/api/scorecard/metrics?metricIds=github.open_prs,jira.open_issues" \ +curl -X GET "{{url}}/api/scorecard/metrics?metricIds=github.openPrs,jira.openIssues" \ -H "Authorization: Bearer " # Get all metrics from a specific datasource @@ -225,9 +225,9 @@ Returns the latest metric values for a specific catalog entity. #### Query Parameters -| Parameter | Type | Required | Description | -| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------ | -| `metricIds` | string | No | Comma-separated list of metric IDs to filter by (e.g., `github.open_prs,jira.open_issues`) | +| Parameter | Type | Required | Description | +| ----------- | ------ | -------- | ---------------------------------------------------------------------------------------- | +| `metricIds` | string | No | Comma-separated list of metric IDs to filter by (e.g., `github.openPrs,jira.openIssues`) | #### Permissions @@ -236,7 +236,7 @@ Requires `scorecard.metric.read` permission and `catalog.entity.read` permission #### Example Request ```bash -curl -X GET "{{url}}/api/scorecard/metrics/catalog/component/default/my-service?metricIds=github.open_prs" \ +curl -X GET "{{url}}/api/scorecard/metrics/catalog/component/default/my-service?metricIds=github.openPrs" \ -H "Authorization: Bearer " ``` @@ -266,7 +266,7 @@ curl -X GET "{{url}}/api/scorecard/aggregations/openIssuesKpi" \ -H "Authorization: Bearer " # Default aggregation when no KPI is configured (id equals metric id) -curl -X GET "{{url}}/api/scorecard/aggregations/github.open_prs" \ +curl -X GET "{{url}}/api/scorecard/aggregations/github.openPrs" \ -H "Authorization: Bearer " ``` @@ -310,8 +310,8 @@ Requires `scorecard.metric.read` permission. Additionally: #### Example Request ```bash -# Deprecated — prefer GET /aggregations/github.open_prs (or your KPI id) -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations" \ +# Deprecated — prefer GET /aggregations/github.openPrs (or your KPI id) +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations" \ -H "Authorization: Bearer " ``` diff --git a/workspaces/scorecard/plugins/scorecard-backend/__fixtures__/mockProviders.ts b/workspaces/scorecard/plugins/scorecard-backend/__fixtures__/mockProviders.ts index 98eaed269b..32ba987234 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/__fixtures__/mockProviders.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/__fixtures__/mockProviders.ts @@ -122,7 +122,7 @@ export class MockBooleanProvider extends MockMetricProvider<'boolean'> { } } export const githubNumberProvider = new MockNumberProvider( - 'github.number_metric', + 'github.numberMetric', 'github', 'Github Number Metric', ); @@ -135,7 +135,7 @@ export const githubNumberMetricMetadata = { }; export const jiraBooleanProvider = new MockBooleanProvider( - 'jira.boolean_metric', + 'jira.booleanMetric', 'jira', ); diff --git a/workspaces/scorecard/plugins/scorecard-backend/docs/aggregation.md b/workspaces/scorecard/plugins/scorecard-backend/docs/aggregation.md index 945d8050d1..30c1ccce36 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/docs/aggregation.md +++ b/workspaces/scorecard/plugins/scorecard-backend/docs/aggregation.md @@ -126,7 +126,7 @@ Requires `scorecard.metric.read` permission. Additionally: ```bash # Get aggregated metrics for a specific metric -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations" \ -H "Authorization: Bearer " ``` diff --git a/workspaces/scorecard/plugins/scorecard-backend/docs/drill-down.md b/workspaces/scorecard/plugins/scorecard-backend/docs/drill-down.md index d7d9fc1433..709071218d 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/docs/drill-down.md +++ b/workspaces/scorecard/plugins/scorecard-backend/docs/drill-down.md @@ -6,7 +6,7 @@ The Scorecard plugin provides a drill-down endpoint that returns detailed entity High-level aggregation for homepage KPIs uses **`GET /aggregations/:aggregationId`** (see [aggregation.md](./aggregation.md)). Drill-down is **metric-scoped**: the endpoint **`/metrics/:metricId/catalog/aggregations/entities`** lists entities and values for a single **metric id** (not a KPI id). -**Note:** If the homepage card uses a KPI key (for example **`openPrsWeightedKpi`**) with **`type: average`**, drill-down still uses the KPI’s configured **`metricId`** (e.g. **`github.open_prs`**) in this path—not the KPI id. +**Note:** If the homepage card uses a KPI key (for example **`openPrsWeightedKpi`**) with **`type: average`**, drill-down still uses the KPI’s configured **`metricId`** (e.g. **`github.openPrs`**) in this path—not the KPI id. The drill-down endpoint provides a detailed view of entities and their metric values. It allows managers and platform engineers to: @@ -26,9 +26,9 @@ Returns a paginated list of entities with their metric values, enriched with cat #### Path Parameters -| Parameter | Type | Required | Description | -| ---------- | ------ | -------- | ---------------------------------------------- | -| `metricId` | string | Yes | The ID of the metric (e.g., `github.open_prs`) | +| Parameter | Type | Required | Description | +| ---------- | ------ | -------- | --------------------------------------------- | +| `metricId` | string | Yes | The ID of the metric (e.g., `github.openPrs`) | #### Query Parameters @@ -99,7 +99,7 @@ type EntityMetricDetail = { Get the first page of entities for a metric: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -108,7 +108,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Get only entities in error state: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?status=error&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?status=error&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -117,14 +117,14 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Get entities owned by a specific team: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?owner=group:default/platform&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?owner=group:default/platform&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` Get entities owned by multiple teams (repeat the `owner` parameter): ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?owner=group:default/platform&owner=group:default/backend&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?owner=group:default/platform&owner=group:default/backend&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -133,7 +133,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Get only Component entities: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?kind=Component&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?kind=Component&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -142,7 +142,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Search for entities with "service" in their name: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?entityName=service&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?entityName=service&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -151,7 +151,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Get entities in a specific namespace: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?namespace=staging&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?namespace=staging&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -160,28 +160,28 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Sort by metric value (highest first): ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?sortBy=metricValue&sortOrder=desc&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?sortBy=metricValue&sortOrder=desc&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` Sort by entity name alphabetically: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?sortBy=entityName&sortOrder=asc&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?sortBy=entityName&sortOrder=asc&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` Sort by namespace alphabetically: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?sortBy=namespace&sortOrder=asc&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?sortBy=namespace&sortOrder=asc&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` Sort by status alphabetically to group entities by threshold result: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?sortBy=status&sortOrder=asc&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?sortBy=status&sortOrder=asc&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -190,7 +190,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ Get Component entities with errors for a specific team, sorted by metric value: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?owner=group:default/platform&status=error&kind=Component&namespace=staging&sortBy=metricValue&sortOrder=desc&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?owner=group:default/platform&status=error&kind=Component&namespace=staging&sortBy=metricValue&sortOrder=desc&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` @@ -198,7 +198,7 @@ curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/ ```json { - "metricId": "github.open_prs", + "metricId": "github.openPrs", "metricMetadata": { "title": "Open Pull Requests", "description": "Number of open pull requests in GitHub", @@ -419,7 +419,7 @@ When no entities match the filters: ```json { - "metricId": "github.open_prs", + "metricId": "github.openPrs", "metricMetadata": { ... }, "entities": [], "pagination": { @@ -448,7 +448,7 @@ The timestamp represents when the metric provider last successfully fetched and A manager sees an aggregated scorecard showing 50 entities with errors. They drill down to see which specific services need attention: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?status=error&sortBy=metricValue&sortOrder=desc&page=1&pageSize=20" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?status=error&sortBy=metricValue&sortOrder=desc&page=1&pageSize=20" \ -H "Authorization: Bearer " ``` @@ -459,7 +459,7 @@ This returns the 20 entities with the most severe issues (highest metric values A team lead wants to see only their team's entities: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/jira.open_issues/catalog/aggregations/entities?owner=group:default/backend&sortBy=timestamp&sortOrder=asc" \ +curl -X GET "{{url}}/api/scorecard/metrics/jira.openIssues/catalog/aggregations/entities?owner=group:default/backend&sortBy=timestamp&sortOrder=asc" \ -H "Authorization: Bearer " ``` @@ -481,7 +481,7 @@ This returns API entities with security warnings, helping prioritize security im An engineer wants to see only their owned entities with issues. The frontend passes the user's `ownershipEntityRefs` (user ref + group memberships) as repeated `owner` params: ```bash -curl -X GET "{{url}}/api/scorecard/metrics/github.open_prs/catalog/aggregations/entities?owner=user:default/alice&owner=group:default/platform&page=1&pageSize=10" \ +curl -X GET "{{url}}/api/scorecard/metrics/github.openPrs/catalog/aggregations/entities?owner=user:default/alice&owner=group:default/platform&page=1&pageSize=10" \ -H "Authorization: Bearer " ``` diff --git a/workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md b/workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md index fb93aac7a6..fb3b869086 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md +++ b/workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md @@ -144,7 +144,7 @@ scorecard.io/{providerId}.thresholds.rules.{thresholdKey}: '{expression}' Where: -- `{providerId}`: The metric provider ID (e.g., `github.open_prs`) +- `{providerId}`: The metric provider ID (e.g., `github.openPrs`) - `{thresholdKey}`: The threshold category (e.g., `success`, `warning`, `error`) - `{expression}`: The threshold expression (e.g., `>10`, `==true`, `5-15`) diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/actions/getEntityMetrics.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/actions/getEntityMetrics.test.ts index 88bd873104..15a245083f 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/actions/getEntityMetrics.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/actions/getEntityMetrics.test.ts @@ -41,7 +41,7 @@ describe('createGetEntityMetricsAction', () => { const mockMetrics = [ { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'Open PRs', @@ -200,7 +200,7 @@ describe('createGetEntityMetricsAction', () => { const conditions = { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.open_prs'] }, + params: { metricIds: ['github.openPrs'] }, }; mockPermissions.authorizeConditional.mockResolvedValue([ { @@ -213,7 +213,7 @@ describe('createGetEntityMetricsAction', () => { const filteredMetrics = [ { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'Open PRs', diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/actions/listMetrics.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/actions/listMetrics.test.ts index 14ba4a7df0..83eeed8d6f 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/actions/listMetrics.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/actions/listMetrics.test.ts @@ -38,7 +38,7 @@ describe('createListMetricsAction', () => { const metrics = [ { - id: 'github.open_prs', + id: 'github.openPrs', title: 'Open PRs', description: 'Number of open pull requests', type: 'number' as const, @@ -95,7 +95,7 @@ describe('createListMetricsAction', () => { const conditions = { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.open_prs'] }, + params: { metricIds: ['github.openPrs'] }, }; mockPermissions.authorizeConditional.mockResolvedValue([ { @@ -108,7 +108,7 @@ describe('createListMetricsAction', () => { const allMetrics = [ { - id: 'github.open_prs', + id: 'github.openPrs', title: 'Open PRs', description: 'Number of open pull requests', type: 'number' as const, diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/middlewares/validateQueryAndParams.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/middlewares/validateQueryAndParams.test.ts index 4f62aef38c..61db779ad1 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/middlewares/validateQueryAndParams.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/middlewares/validateQueryAndParams.test.ts @@ -81,7 +81,7 @@ describe('Validators', () => { }); it('should call next when metricIds is a valid string', () => { - const req = mockReq({ query: { metricIds: 'github.open_prs' } }); + const req = mockReq({ query: { metricIds: 'github.openPrs' } }); validateMetricIdsQueryParams(req, res, next); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/permissions/permissionUtils.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/permissions/permissionUtils.test.ts index 53937d6cae..4ab62ccf63 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/permissions/permissionUtils.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/permissions/permissionUtils.test.ts @@ -119,7 +119,7 @@ describe('permissionUtils', () => { { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.open_prs'] }, + params: { metricIds: ['github.openPrs'] }, }, ], }; @@ -188,7 +188,7 @@ describe('permissionUtils', () => { const mockMetricIdPermissionCondition = { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.open_prs'] }, + params: { metricIds: ['github.openPrs'] }, }; describe('matches', () => { @@ -210,12 +210,9 @@ describe('permissionUtils', () => { not: mockMetricIdPermissionCondition, }; - const matchedMetric = createMockMetric( - 'github.open_prs', - 'GitHub Open PRs', - ); + const matchedMetric = createMockMetric('github.openPrs', 'GitHub Open PRs'); const nonMatchedMetric = createMockMetric( - 'jira.open_issues', + 'jira.openIssues', 'Jira Open Issues', ); @@ -250,8 +247,8 @@ describe('permissionUtils', () => { describe('filterAuthorizedMetrics', () => { const metrics = [ - createMockMetric('github.open_prs', 'GitHub Open PRs'), - createMockMetric('jira.open_issues', 'Jira Open Issues'), + createMockMetric('github.openPrs', 'GitHub Open PRs'), + createMockMetric('jira.openIssues', 'Jira Open Issues'), ]; it('should return all metrics when no filter is provided', () => { @@ -265,7 +262,7 @@ describe('permissionUtils', () => { anyOf: [mockMetricIdPermissionCondition], }); expect(result).toHaveLength(1); - expect(result[0].id).toBe('github.open_prs'); + expect(result[0].id).toBe('github.openPrs'); }); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.test.ts index a616eb76e5..02f3b9b8b5 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.test.ts @@ -44,24 +44,24 @@ describe('MetricProvidersRegistry', () => { expect(() => registry.register(jiraBooleanProvider)).not.toThrow(); expect(registry.listMetrics()).toEqual([ { - id: 'github.number_metric', + id: 'github.numberMetric', ...githubNumberMetricMetadata, }, { - id: 'jira.boolean_metric', + id: 'jira.booleanMetric', ...jiraBooleanMetricMetadata, }, ]); }); it('should throw ConflictError when registering provider with duplicate ID', () => { - const provider1 = new MockNumberProvider('jira.duplicate_id', 'jira'); - const provider2 = new MockBooleanProvider('jira.duplicate_id', 'jira'); + const provider1 = new MockNumberProvider('jira.duplicateId', 'jira'); + const provider2 = new MockBooleanProvider('jira.duplicateId', 'jira'); registry.register(provider1); expect(() => registry.register(provider2)).toThrow( new ConflictError( - "Metric provider with ID 'jira.duplicate_id' has already been registered", + "Metric provider with ID 'jira.duplicateId' has already been registered", ), ); }); @@ -75,13 +75,13 @@ describe('MetricProvidersRegistry', () => { } const invalidProvider = new InvalidProvider( - 'github.test_metric', + 'github.testMetric', 'github', ); expect(() => registry.register(invalidProvider)).toThrow( new Error( - "Invalid metric provider: metric ID 'github.test_metric' returned by getMetricIds() " + + "Invalid metric provider: metric ID 'github.testMetric' returned by getMetricIds() " + 'does not have a corresponding metric in getMetrics()', ), ); @@ -96,27 +96,24 @@ describe('MetricProvidersRegistry', () => { } const invalidProvider = new InvalidProvider( - 'github.test_metric', + 'github.testMetric', 'github', ); // @ts-expect-error - expect error to be thrown expect(() => registry.register(invalidProvider)).toThrow( new Error( - "Invalid metric provider with ID github.test_metric, getMetricType() must match getMetric().type. Expected 'boolean', but got 'number'", + "Invalid metric provider with ID github.testMetric, getMetricType() must match getMetric().type. Expected 'boolean', but got 'number'", ), ); }); it('should throw error when provider ID does not start with datasource ID', () => { - const invalidProvider = new MockNumberProvider( - 'invalid_format', - 'github', - ); + const invalidProvider = new MockNumberProvider('invalidFormat', 'github'); expect(() => registry.register(invalidProvider)).toThrow( new Error( - "Invalid metric provider with ID invalid_format, must have format 'github.' where metric name is not empty", + "Invalid metric provider with ID invalidFormat, must have format 'github.' where metric name is not empty", ), ); }); @@ -126,20 +123,17 @@ describe('MetricProvidersRegistry', () => { expect(() => registry.register(invalidProvider)).toThrow( new Error( - "Invalid metric provider with ID github., must have format 'github.' where metric name is not empty", + "Invalid metric provider with ID github., must have format 'github.' where metric name is not empty", ), ); }); it('should throw error for provider ID missing dot separator', () => { - const invalidProvider = new MockNumberProvider( - 'githubopen_prs', - 'github', - ); + const invalidProvider = new MockNumberProvider('githubopenPrs', 'github'); expect(() => registry.register(invalidProvider)).toThrow( new Error( - "Invalid metric provider with ID githubopen_prs, must have format 'github.' where metric name is not empty", + "Invalid metric provider with ID githubopenPrs, must have format 'github.' where metric name is not empty", ), ); }); @@ -154,12 +148,12 @@ describe('MetricProvidersRegistry', () => { } const invalidProvider = new InvalidThresholdFormatProvider( - 'github.invalid_threshold_format', + 'github.invalidThresholdFormat', 'github', ); expect(() => registry.register(invalidProvider)).toThrow( - 'Invalid default thresholds for metric provider \'github.invalid_threshold_format\'; caused by ThresholdConfigFormatError: Invalid threshold expression: "Invalid expression"', + 'Invalid default thresholds for metric provider \'github.invalidThresholdFormat\'; caused by ThresholdConfigFormatError: Invalid threshold expression: "Invalid expression"', ); }); @@ -229,12 +223,12 @@ describe('MetricProvidersRegistry', () => { it('should throw error when batch provider metric ID has wrong format', () => { class InvalidBatchProvider extends MockBatchBooleanProvider { getMetricIds(): string[] { - return ['invalid_format']; + return ['invalidFormat']; } getMetrics() { return [ { - id: 'invalid_format', + id: 'invalidFormat', title: 'Invalid', description: 'Invalid', type: 'boolean' as const, @@ -250,7 +244,7 @@ describe('MetricProvidersRegistry', () => { ); expect(() => registry.register(invalidProvider)).toThrow( - "Invalid metric provider with ID invalid_format, must have format 'github.' where metric name is not empty", + "Invalid metric provider with ID invalidFormat, must have format 'github.' where metric name is not empty", ); }); }); @@ -260,15 +254,15 @@ describe('MetricProvidersRegistry', () => { it('should return provider for registered provider', () => { registry.register(githubNumberProvider); - const provider = registry.getProvider('github.number_metric'); + const provider = registry.getProvider('github.numberMetric'); expect(provider).toEqual(githubNumberProvider); }); it('should throw NotFoundError for unregistered provider', () => { - expect(() => registry.getProvider('non_existent')).toThrow( + expect(() => registry.getProvider('nonExistent')).toThrow( new NotFoundError( - "No metric provider registered for metric ID 'non_existent'.", + "No metric provider registered for metric ID 'nonExistent'.", ), ); }); @@ -278,18 +272,18 @@ describe('MetricProvidersRegistry', () => { it('should return metric for registered provider', () => { registry.register(githubNumberProvider); - const metric = registry.getMetric('github.number_metric'); + const metric = registry.getMetric('github.numberMetric'); expect(metric).toEqual({ - id: 'github.number_metric', + id: 'github.numberMetric', ...githubNumberMetricMetadata, }); }); it('should throw NotFoundError for unregistered provider', () => { - expect(() => registry.getMetric('non_existent')).toThrow( + expect(() => registry.getMetric('nonExistent')).toThrow( new NotFoundError( - "No metric provider registered for metric ID 'non_existent'.", + "No metric provider registered for metric ID 'nonExistent'.", ), ); }); @@ -312,7 +306,7 @@ describe('MetricProvidersRegistry', () => { registry.register(githubNumberProvider); const result = await registry.calculateMetric( - 'github.number_metric', + 'github.numberMetric', mockEntity, ); @@ -321,10 +315,10 @@ describe('MetricProvidersRegistry', () => { it('should throw NotFoundError for unregistered provider', async () => { await expect( - registry.calculateMetric('non_existent', mockEntity), + registry.calculateMetric('nonExistent', mockEntity), ).rejects.toThrow( new NotFoundError( - "No metric provider registered for metric ID 'non_existent'.", + "No metric provider registered for metric ID 'nonExistent'.", ), ); }); @@ -342,17 +336,17 @@ describe('MetricProvidersRegistry', () => { registry.register(jiraBooleanProvider); const results = await registry.calculateMetrics( - ['github.number_metric', 'jira.boolean_metric'], + ['github.numberMetric', 'jira.booleanMetric'], mockEntity, ); expect(results).toHaveLength(2); expect(results[0]).toEqual({ - metricId: 'github.number_metric', + metricId: 'github.numberMetric', value: 42, }); expect(results[1]).toEqual({ - metricId: 'jira.boolean_metric', + metricId: 'jira.booleanMetric', value: false, }); }); @@ -361,7 +355,7 @@ describe('MetricProvidersRegistry', () => { registry.register(githubNumberProvider); registry.register( new MockNumberProvider( - 'github.open_issues', + 'github.openIssues', 'github', 'GitHub Open Issues', 'Github Open Issues description', @@ -371,17 +365,17 @@ describe('MetricProvidersRegistry', () => { registry.register(jiraBooleanProvider); const results = await registry.calculateMetrics( - ['github.number_metric', 'github.open_issues'], + ['github.numberMetric', 'github.openIssues'], mockEntity, ); expect(results).toHaveLength(2); expect(results[0]).toEqual({ - metricId: 'github.number_metric', + metricId: 'github.numberMetric', value: 42, }); expect(results[1]).toEqual({ - metricId: 'github.open_issues', + metricId: 'github.openIssues', value: 10, }); }); @@ -390,21 +384,21 @@ describe('MetricProvidersRegistry', () => { registry.register(githubNumberProvider); const results = await registry.calculateMetrics( - ['github.number_metric', 'non_existent'], + ['github.numberMetric', 'nonExistent'], mockEntity, ); expect(results).toHaveLength(2); expect(results[0]).toEqual({ - metricId: 'github.number_metric', + metricId: 'github.numberMetric', value: 42, }); expect(results[1]).toEqual({ - metricId: 'non_existent', + metricId: 'nonExistent', error: expect.any(NotFoundError), }); expect(results[1].error?.message).toBe( - "No metric provider registered for metric ID 'non_existent'.", + "No metric provider registered for metric ID 'nonExistent'.", ); }); }); @@ -456,15 +450,15 @@ describe('MetricProvidersRegistry', () => { const metrics = registry.listMetrics(); expect(metrics).toHaveLength(2); - expect(metrics[0].id).toBe('github.number_metric'); - expect(metrics[1].id).toBe('jira.boolean_metric'); + expect(metrics[0].id).toBe('github.numberMetric'); + expect(metrics[1].id).toBe('jira.booleanMetric'); }); it('should return filtered metrics', () => { - const metrics = registry.listMetrics(['jira.boolean_metric']); + const metrics = registry.listMetrics(['jira.booleanMetric']); expect(metrics).toHaveLength(1); - expect(metrics[0].id).toBe('jira.boolean_metric'); + expect(metrics[0].id).toBe('jira.booleanMetric'); }); it('should return empty array when all provider IDs are non-existent', () => { @@ -478,15 +472,15 @@ describe('MetricProvidersRegistry', () => { it('should return only existing metrics when mix of existing and non-existent IDs', () => { const metrics = registry.listMetrics([ - 'github.number_metric', + 'github.numberMetric', 'non.existent.metric', - 'jira.boolean_metric', + 'jira.booleanMetric', 'another.non.existent', ]); expect(metrics).toHaveLength(2); - expect(metrics[0].id).toBe('github.number_metric'); - expect(metrics[1].id).toBe('jira.boolean_metric'); + expect(metrics[0].id).toBe('github.numberMetric'); + expect(metrics[1].id).toBe('jira.booleanMetric'); }); describe('with batch providers', () => { @@ -504,7 +498,7 @@ describe('MetricProvidersRegistry', () => { 'filecheck.readme', 'filecheck.license', 'filecheck.codeowners', - 'jira.boolean_metric', + 'jira.booleanMetric', ]); }); @@ -536,7 +530,7 @@ describe('MetricProvidersRegistry', () => { registry.register(jiraBooleanProvider); registry.register( new MockNumberProvider( - 'github.open_issues', + 'github.openIssues', 'github', 'GitHub Open Issues', ), @@ -554,15 +548,15 @@ describe('MetricProvidersRegistry', () => { const metrics = registry.listMetricsByDatasource('github'); expect(metrics).toHaveLength(2); - expect(metrics[0].id).toBe('github.number_metric'); - expect(metrics[1].id).toBe('github.open_issues'); + expect(metrics[0].id).toBe('github.numberMetric'); + expect(metrics[1].id).toBe('github.openIssues'); }); it('should return metrics for jira datasource', () => { const metrics = registry.listMetricsByDatasource('jira'); expect(metrics).toHaveLength(1); - expect(metrics[0].id).toBe('jira.boolean_metric'); + expect(metrics[0].id).toBe('jira.booleanMetric'); }); it('should return empty array when datasource does not exist', () => { @@ -598,7 +592,7 @@ describe('MetricProvidersRegistry', () => { const githubMetrics = registry.listMetricsByDatasource('github'); expect(githubMetrics).toHaveLength(1); - expect(githubMetrics[0].id).toBe('github.number_metric'); + expect(githubMetrics[0].id).toBe('github.numberMetric'); }); it('should not duplicate metrics from batch providers in datasource listing', () => { diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.ts b/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.ts index 7b0c9d3ccd..1633dc743c 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/providers/MetricProvidersRegistry.ts @@ -61,12 +61,12 @@ export class MetricProvidersRegistry { ); } - // Validate: Provider ID format (datasource.metric_name) + // Validate: Provider ID format (datasource.metricName) const expectedPrefix = `${providerDatasource}.`; if (!metricId.startsWith(expectedPrefix) || metricId === expectedPrefix) { throw new Error( `Invalid metric provider with ID ${metricId}, must have format ` + - `'${providerDatasource}.' where metric name is not empty`, + `'${providerDatasource}.' where metric name is not empty`, ); } diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/index.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/index.test.ts index 296aa297b0..e627a4e451 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/index.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/index.test.ts @@ -33,8 +33,8 @@ import { ThresholdResolver } from '../threshold/ThresholdResolver'; jest.mock('./tasks/CleanupExpiredMetricsTask'); jest.mock('./tasks/PullMetricsByProviderTask'); -const numberProvider = new MockNumberProvider('github.test_metric', 'github'); -const booleanProvider = new MockBooleanProvider('jira.test_metric', 'jira'); +const numberProvider = new MockNumberProvider('github.testMetric', 'github'); +const booleanProvider = new MockBooleanProvider('jira.testMetric', 'jira'); describe('Scheduler', () => { let mockCleanupTask: jest.Mocked; @@ -210,11 +210,11 @@ describe('Scheduler', () => { expect(initializedTasks).toEqual([ { - name: 'github.test_metric', + name: 'github.testMetric', task: mockPullTask, }, { - name: 'jira.test_metric', + name: 'jira.testMetric', task: mockPullTask, }, ]); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.test.ts index 391f93eff6..758c1bbd7a 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.test.ts @@ -68,7 +68,7 @@ describe('PullMetricsByProviderTask', () => { }); mockCatalog = catalogServiceMock.mock(); mockAuth = mockServices.auth.mock(); - mockProvider = new MockNumberProvider('github.test_metric', 'github'); + mockProvider = new MockNumberProvider('github.testMetric', 'github'); mockThresholdEvaluator = { getFirstMatchingThreshold: jest.fn(), @@ -137,7 +137,7 @@ describe('PullMetricsByProviderTask', () => { it('should get scheduled from config', () => { expect((task as any).getScheduleFromConfig).toHaveBeenCalledWith( - 'scorecard.plugins.github.test_metric.schedule', + 'scorecard.plugins.github.testMetric.schedule', ); }); @@ -151,7 +151,7 @@ describe('PullMetricsByProviderTask', () => { it('should run the task runner', () => { expect(mockTaskRunner.run).toHaveBeenCalledTimes(1); expect(mockTaskRunner.run).toHaveBeenCalledWith({ - id: 'github.test_metric', + id: 'github.testMetric', fn: expect.any(Function), }); }); @@ -190,7 +190,7 @@ describe('PullMetricsByProviderTask', () => { await (task as any).pullProviderMetrics(mockProvider, mockLogger); expect(mockLogger.info).toHaveBeenNthCalledWith( 1, - `Pulling metrics for github.test_metric`, + `Pulling metrics for github.testMetric`, ); }); @@ -267,14 +267,14 @@ describe('PullMetricsByProviderTask', () => { entity_kind: 'component', entity_namespace: undefined, entity_owner: undefined, - metric_id: 'github.test_metric', + metric_id: 'github.testMetric', timestamp: new Date('2024-01-15T12:00:00.000Z'), value: 42, status: 'success', }, { catalog_entity_ref: 'component:default/test2', - metric_id: 'github.test_metric', + metric_id: 'github.testMetric', entity_kind: 'component', entity_namespace: undefined, entity_owner: undefined, @@ -384,7 +384,7 @@ describe('PullMetricsByProviderTask', () => { await (task as any).pullProviderMetrics(mockProvider, mockLogger); expect(mockLogger.info).toHaveBeenCalledWith( - `Completed metric pull for github.test_metric: processed 2 entities`, + `Completed metric pull for github.testMetric: processed 2 entities`, ); }); @@ -395,7 +395,7 @@ describe('PullMetricsByProviderTask', () => { metadata: { name: 'excluded-entity', annotations: { - 'scorecard.io/disabled-metrics': 'github.test_metric', + 'scorecard.io/disabled-metrics': 'github.testMetric', }, }, }; diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts index 4617a65531..0b9f68119c 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts @@ -55,13 +55,13 @@ import { ThresholdResolver } from '../threshold/ThresholdResolver'; jest.mock('../permissions/permissionUtils'); -const provider = new MockNumberProvider('github.important_metric', 'github'); +const provider = new MockNumberProvider('github.importantMetric', 'github'); const latestEntityMetric = [ { id: 1, catalog_entity_ref: 'component:default/test-component', - metric_id: 'github.important_metric', + metric_id: 'github.importantMetric', value: 42, timestamp: new Date('2024-01-15T12:00:00.000Z'), error_message: null, @@ -70,7 +70,7 @@ const latestEntityMetric = [ ] as DbMetricValue[]; const aggregatedMetric: DbAggregatedMetric = { - metric_id: 'github.important_metric', + metric_id: 'github.importantMetric', total: 2, max_timestamp: new Date('2024-01-15T12:00:00.000Z'), statusCounts: { @@ -82,8 +82,8 @@ const aggregatedMetric: DbAggregatedMetric = { }; const metricsList = [ - { id: 'github.important_metric' }, - { id: 'github.number_metric' }, + { id: 'github.importantMetric' }, + { id: 'github.numberMetric' }, ] as Metric[]; const permissionsFilter = { @@ -91,7 +91,7 @@ const permissionsFilter = { { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.important_metric'] }, + params: { metricIds: ['github.importantMetric'] }, }, ], } as PermissionCriteria>; @@ -135,7 +135,7 @@ describe('CatalogMetricService', () => { mockedLogger = mockServices.logger.mock(); (permissionUtils.filterAuthorizedMetrics as jest.Mock).mockReturnValue([ - { id: 'github.important_metric' }, + { id: 'github.importantMetric' }, ]); mockedThresholdResolver = { @@ -182,23 +182,23 @@ describe('CatalogMetricService', () => { describe('getLatestEntityMetrics', () => { it('should handle multiple metrics correctly', async () => { const secondProvider = new MockNumberProvider( - 'github.number_metric', + 'github.numberMetric', 'github', ); mockedRegistry.getProvider.mockImplementation(id => - id === 'github.important_metric' ? provider : secondProvider, + id === 'github.importantMetric' ? provider : secondProvider, ); mockedRegistry.getMetric.mockImplementation(id => - id === 'github.important_metric' + id === 'github.importantMetric' ? provider.getMetric() : secondProvider.getMetric(), ); const multipleMetrics = [ - { ...latestEntityMetric[0], metric_id: 'github.important_metric' }, + { ...latestEntityMetric[0], metric_id: 'github.importantMetric' }, { ...latestEntityMetric[0], - metric_id: 'github.number_metric', + metric_id: 'github.numberMetric', value: 10, }, ]; @@ -207,8 +207,8 @@ describe('CatalogMetricService', () => { ); (permissionUtils.filterAuthorizedMetrics as jest.Mock).mockReturnValue([ - { id: 'github.important_metric' }, - { id: 'github.number_metric' }, + { id: 'github.importantMetric' }, + { id: 'github.numberMetric' }, ] as Metric[]); const result = await service.getLatestEntityMetrics( @@ -216,13 +216,13 @@ describe('CatalogMetricService', () => { ); expect(result).toHaveLength(2); - expect(result[0].id).toBe('github.important_metric'); - expect(result[1].id).toBe('github.number_metric'); + expect(result[0].id).toBe('github.importantMetric'); + expect(result[1].id).toBe('github.numberMetric'); }); it('should get own service credentials', async () => { await service.getLatestEntityMetrics('component:default/test-component', [ - 'github.important_metric', + 'github.importantMetric', ]); expect(mockedAuth.getOwnServiceCredentials).toHaveBeenCalledWith(); @@ -252,12 +252,12 @@ describe('CatalogMetricService', () => { it('should filter authorized metrics for specific provider IDs', async () => { await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], permissionsFilter, ); expect(permissionUtils.filterAuthorizedMetrics).toHaveBeenCalledWith( - [{ id: 'github.important_metric' }], + [{ id: 'github.importantMetric' }], permissionsFilter, ); }); @@ -270,19 +270,19 @@ describe('CatalogMetricService', () => { ); expect(permissionUtils.filterAuthorizedMetrics).toHaveBeenCalledWith( - [{ id: 'github.important_metric' }, { id: 'github.number_metric' }], + [{ id: 'github.importantMetric' }, { id: 'github.numberMetric' }], permissionsFilter, ); }); it('should read latest entity metric values', async () => { await service.getLatestEntityMetrics('component:default/test-component', [ - 'github.important_metric', + 'github.importantMetric', ]); expect(mockedDatabase.readLatestEntityMetricValues).toHaveBeenCalledWith( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); }); @@ -291,7 +291,7 @@ describe('CatalogMetricService', () => { const result = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); expect(result).toEqual([]); @@ -299,27 +299,27 @@ describe('CatalogMetricService', () => { it('should get provider by metric ID', async () => { await service.getLatestEntityMetrics('component:default/test-component', [ - 'github.important_metric', + 'github.importantMetric', ]); expect(mockedRegistry.getProvider).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', ); }); it('should get metric from registry', async () => { await service.getLatestEntityMetrics('component:default/test-component', [ - 'github.important_metric', + 'github.importantMetric', ]); expect(mockedRegistry.getMetric).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', ); }); it('should merge entity and provider thresholds', async () => { await service.getLatestEntityMetrics('component:default/test-component', [ - 'github.important_metric', + 'github.importantMetric', ]); expect( @@ -334,7 +334,7 @@ describe('CatalogMetricService', () => { const newResult = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); expect(newResult).toHaveLength(1); @@ -355,7 +355,7 @@ describe('CatalogMetricService', () => { const newResult = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); expect(newResult[0].status).toBe('error'); @@ -378,7 +378,7 @@ describe('CatalogMetricService', () => { const newResult = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); expect(newResult[0].status).toBe('success'); @@ -392,7 +392,7 @@ describe('CatalogMetricService', () => { it('should return metric result', async () => { const result = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); expect(result.length).toBe(1); @@ -401,7 +401,7 @@ describe('CatalogMetricService', () => { expect(resultMetric).toEqual( expect.objectContaining({ - id: 'github.important_metric', + id: 'github.importantMetric', status: 'success', }), ); @@ -438,7 +438,7 @@ describe('CatalogMetricService', () => { const newResult = await service.getLatestEntityMetrics( 'component:default/test-component', - ['github.important_metric'], + ['github.importantMetric'], ); const thresholdResult = newResult[0].result.thresholdResult; @@ -543,7 +543,7 @@ describe('CatalogMetricService', () => { 'component:default/test-component', 'component:default/test-component-2', ], - 'github.important_metric', + 'github.importantMetric', ); }); @@ -568,7 +568,7 @@ describe('CatalogMetricService', () => { 'component:default/test-component', 'component:default/test-component-2', ], - 'github.important_metric', + 'github.importantMetric', ); }); @@ -581,7 +581,7 @@ describe('CatalogMetricService', () => { await expect( service.getAggregatedMetricByEntityRefs( ['component:default/test-component'], - 'github.important_metric', + 'github.importantMetric', 'unknownAggregation', ), ).rejects.toThrow('Unsupported aggregation type: unknownAggregation'); @@ -603,7 +603,7 @@ describe('CatalogMetricService', () => { 'component:default/f', 'component:default/g', ], - 'github.important_metric', + 'github.importantMetric', aggregationTypes.statusGrouped, ); @@ -617,7 +617,7 @@ describe('CatalogMetricService', () => { beforeEach(async () => { result = await loader.loadStatusGroupedMetricByEntityRefs( [], - 'github.important_metric', + 'github.importantMetric', ); }); @@ -649,7 +649,7 @@ describe('CatalogMetricService', () => { { id: 1, catalog_entity_ref: 'component:default/service-a', - metric_id: 'github.important_metric', + metric_id: 'github.importantMetric', value: 15, timestamp: new Date('2024-01-15T12:00:00.000Z'), error_message: null, @@ -661,7 +661,7 @@ describe('CatalogMetricService', () => { { id: 2, catalog_entity_ref: 'component:default/service-b', - metric_id: 'github.important_metric', + metric_id: 'github.importantMetric', value: 8, timestamp: new Date('2024-01-15T11:00:00.000Z'), error_message: null, @@ -673,7 +673,7 @@ describe('CatalogMetricService', () => { { id: 3, catalog_entity_ref: 'component:staging/service-c', - metric_id: 'github.important_metric', + metric_id: 'github.importantMetric', value: 3, timestamp: new Date('2024-01-15T10:00:00.000Z'), error_message: null, @@ -718,7 +718,7 @@ describe('CatalogMetricService', () => { it('should fetch entity metrics with default options', async () => { const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -726,7 +726,7 @@ describe('CatalogMetricService', () => { }, ); - expect(result.metricId).toBe('github.important_metric'); + expect(result.metricId).toBe('github.importantMetric'); expect(result.entities).toHaveLength(3); expect(result.pagination).toEqual({ page: 1, @@ -744,7 +744,7 @@ describe('CatalogMetricService', () => { it('should enrich entities with catalog metadata', async () => { const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -766,7 +766,7 @@ describe('CatalogMetricService', () => { it('should always query the full fetchable window from the database and paginate in-memory', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 2, @@ -775,14 +775,14 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { pagination: { limit: 10_000, offset: 0 } }, ); }); it('should filter by status at database level', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { status: 'error', @@ -792,14 +792,14 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { status: 'error', pagination: { limit: 10_000, offset: 0 } }, ); }); it('should filter by kind at database level', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { kind: 'Component', @@ -809,14 +809,14 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { entityKind: 'Component', pagination: { limit: 10_000, offset: 0 } }, ); }); it('should filter by owner at database level', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { owner: ['team:default/platform'], @@ -826,7 +826,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { entityOwner: ['team:default/platform'], pagination: { limit: 10_000, offset: 0 }, @@ -840,7 +840,7 @@ describe('CatalogMetricService', () => { ]); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { entityName: 'service-a', @@ -850,7 +850,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { entityName: 'service-a', pagination: { limit: 10_000, offset: 0 } }, ); @@ -861,7 +861,7 @@ describe('CatalogMetricService', () => { it('should pass entityName to database for filtering', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { entityName: 'SERVICE', @@ -871,14 +871,14 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { entityName: 'SERVICE', pagination: { limit: 10_000, offset: 0 } }, ); }); it('should sort by entityName ascending', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { sortBy: 'entityName', @@ -889,7 +889,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { sortBy: 'entityName', sortOrder: 'asc', @@ -900,7 +900,7 @@ describe('CatalogMetricService', () => { it('should sort by metricValue descending', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { sortBy: 'metricValue', @@ -911,7 +911,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { sortBy: 'metricValue', sortOrder: 'desc', @@ -922,7 +922,7 @@ describe('CatalogMetricService', () => { it('should sort by timestamp descending by default', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -932,14 +932,14 @@ describe('CatalogMetricService', () => { // When no sortBy/sortOrder are supplied the DB defaults to timestamp desc expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { pagination: { limit: 10_000, offset: 0 } }, ); }); it('should sort by namespace ascending', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { sortBy: 'namespace', @@ -950,7 +950,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { sortBy: 'namespace', sortOrder: 'asc', @@ -961,7 +961,7 @@ describe('CatalogMetricService', () => { it('should sort by namespace descending', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { sortBy: 'namespace', @@ -972,7 +972,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { sortBy: 'namespace', sortOrder: 'desc', @@ -990,7 +990,7 @@ describe('CatalogMetricService', () => { }); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { namespace: 'staging', @@ -1000,7 +1000,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { entityNamespace: 'staging', pagination: { limit: 10_000, offset: 0 }, @@ -1014,7 +1014,7 @@ describe('CatalogMetricService', () => { it('should include entityNamespace in enriched entity response', async () => { const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1039,7 +1039,7 @@ describe('CatalogMetricService', () => { }); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { status: 'success', @@ -1053,7 +1053,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { status: 'success', entityKind: 'API', @@ -1076,7 +1076,7 @@ describe('CatalogMetricService', () => { ]); await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { sortBy: 'metricValue', @@ -1088,7 +1088,7 @@ describe('CatalogMetricService', () => { // Null handling (nulls-last) is delegated to the DB via orderByRaw expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { sortBy: 'metricValue', sortOrder: 'desc', @@ -1099,7 +1099,7 @@ describe('CatalogMetricService', () => { it('should batch-fetch entities using getEntitiesByRefs', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1127,7 +1127,7 @@ describe('CatalogMetricService', () => { }); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1155,7 +1155,7 @@ describe('CatalogMetricService', () => { ); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1179,13 +1179,13 @@ describe('CatalogMetricService', () => { it('should pass null to database for unscoped query (avoids catalog enumeration)', async () => { await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, limit: 10 }, ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { pagination: { limit: 10_000, offset: 0 } }, ); }); @@ -1197,7 +1197,7 @@ describe('CatalogMetricService', () => { }); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, limit: 10 }, ); @@ -1220,7 +1220,7 @@ describe('CatalogMetricService', () => { ]); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { status: 'error', @@ -1234,7 +1234,7 @@ describe('CatalogMetricService', () => { ); expect(mockedDatabase.readEntityMetricsWithFilters).toHaveBeenCalledWith( - 'github.important_metric', + 'github.importantMetric', { status: 'error', entityKind: 'Component', @@ -1253,7 +1253,7 @@ describe('CatalogMetricService', () => { mockedDatabase.readEntityMetricsWithFilters.mockResolvedValue([]); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1288,7 +1288,7 @@ describe('CatalogMetricService', () => { ]); const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, @@ -1305,7 +1305,7 @@ describe('CatalogMetricService', () => { it('should include metric metadata in response', async () => { const result = await service.getEntityMetricDetails( - 'github.important_metric', + 'github.importantMetric', mockCredentials, { page: 1, diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts index b824ec1419..39424df841 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts @@ -232,7 +232,7 @@ export class CatalogMetricService { * database-level sorting, and in-memory pagination over the permission-filtered result set. * Returns empty entities if the catalog is unavailable (fail-secure). * - * @param metricId - Metric ID to fetch (e.g., "github.open_prs") + * @param metricId - Metric ID to fetch (e.g., "github.openPrs") * @param options - Query options for filtering, sorting, and pagination * @param options.status - Filter by threshold status (database-level) * @param options.owner - Filter by owner entity reference (database-level) diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/AggregationsService.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/AggregationsService.test.ts index 38fd55c34f..fa2a62bdde 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/AggregationsService.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/AggregationsService.test.ts @@ -39,7 +39,7 @@ function createDatabaseMock( describe('AggregationsService', () => { const metric = { - id: 'github.open_prs', + id: 'github.openPrs', title: 'Open PRs', description: 'desc', type: 'number', @@ -168,13 +168,13 @@ describe('AggregationsService', () => { logger, }); - const cfg = service.getAggregationConfig('github.open_prs'); + const cfg = service.getAggregationConfig('github.openPrs'); - expect(cfg.id).toBe('github.open_prs'); - expect(cfg.metricId).toBe('github.open_prs'); + expect(cfg.id).toBe('github.openPrs'); + expect(cfg.metricId).toBe('github.openPrs'); expect(cfg.type).toBe(aggregationTypes.statusGrouped); expect(logger.warn).toHaveBeenCalledWith( - expect.stringContaining('github.open_prs'), + expect.stringContaining('github.openPrs'), ); }); @@ -186,7 +186,7 @@ describe('AggregationsService', () => { title: 'KPI title', description: 'KPI desc', type: aggregationTypes.average, - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { error: 0, warning: 50, success: 100 }, }, @@ -203,7 +203,7 @@ describe('AggregationsService', () => { const cfg = service.getAggregationConfig('myKpi'); - expect(cfg.metricId).toBe('github.open_prs'); + expect(cfg.metricId).toBe('github.openPrs'); expect(cfg.type).toBe(aggregationTypes.average); expect(cfg.title).toBe('KPI title'); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/averageAggregationStrategy.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/averageAggregationStrategy.test.ts index 72629f1a47..32ccdaeb73 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/averageAggregationStrategy.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/averageAggregationStrategy.test.ts @@ -26,7 +26,7 @@ import { AverageAggregationStrategy } from './AverageAggregationStrategy'; describe('AverageAggregationStrategy', () => { const metric = { - id: 'github.open_prs', + id: 'github.openPrs', title: 'Open PRs', description: 'desc', type: 'number', diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/statusGroupedAggregationStrategy.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/statusGroupedAggregationStrategy.test.ts index d60eb3a83f..c2f8eac937 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/statusGroupedAggregationStrategy.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/aggregations/strategies/statusGroupedAggregationStrategy.test.ts @@ -26,7 +26,7 @@ import { DatabaseMetricValues } from '../../../database/DatabaseMetricValues'; describe('StatusGroupedAggregationStrategy', () => { const metric = { - id: 'github.open_prs', + id: 'github.openPrs', title: 'Open PRs', description: 'desc', type: 'number', diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/service/router.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/service/router.test.ts index 3c2750b8e3..979f03611a 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/service/router.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/service/router.test.ts @@ -92,7 +92,7 @@ const CONDITIONAL_POLICY_DECISION: PolicyDecision = { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', params: { - metricIds: ['github.open_prs', 'github.open_issues'], + metricIds: ['github.openPrs', 'github.openIssues'], }, }, ], @@ -170,12 +170,12 @@ describe('createRouter', () => { describe('GET /metrics', () => { beforeEach(() => { const githubProvider1 = new MockNumberProvider( - 'github.open_prs', + 'github.openPrs', 'github', 'GitHub Open PRs', ); const githubProvider2 = new MockNumberProvider( - 'github.open_issues', + 'github.openIssues', 'github', 'GitHub Open Issues', ); @@ -198,14 +198,14 @@ describe('createRouter', () => { expect(response.body.metrics).toHaveLength(3); const metricIds = response.body.metrics.map((m: Metric) => m.id); - expect(metricIds).toContain('github.open_prs'); - expect(metricIds).toContain('github.open_issues'); + expect(metricIds).toContain('github.openPrs'); + expect(metricIds).toContain('github.openIssues'); expect(metricIds).toContain('sonar.quality'); }); it('should return metrics filtered by metricIds - single metric', async () => { const response = await request(app).get( - '/metrics?metricIds=github.open_prs', + '/metrics?metricIds=github.openPrs', ); expect(response.status).toBe(200); @@ -213,12 +213,12 @@ describe('createRouter', () => { expect(response.body.metrics).toHaveLength(1); const metricIds = response.body.metrics.map((m: Metric) => m.id); - expect(metricIds).toContain('github.open_prs'); + expect(metricIds).toContain('github.openPrs'); }); it('should return metrics filtered by metricIds - multiple metrics', async () => { const response = await request(app).get( - '/metrics?metricIds=github.open_prs,github.open_issues', + '/metrics?metricIds=github.openPrs,github.openIssues', ); expect(response.status).toBe(200); @@ -226,13 +226,13 @@ describe('createRouter', () => { expect(response.body.metrics).toHaveLength(2); const metricIds = response.body.metrics.map((m: Metric) => m.id); - expect(metricIds).toContain('github.open_prs'); - expect(metricIds).toContain('github.open_issues'); + expect(metricIds).toContain('github.openPrs'); + expect(metricIds).toContain('github.openIssues'); }); it('should return metrics filtered by metricIds with whitespace', async () => { const response = await request(app).get( - '/metrics?metricIds=github.open_prs, github.open_issues', + '/metrics?metricIds=github.openPrs, github.openIssues', ); expect(response.status).toBe(200); @@ -240,8 +240,8 @@ describe('createRouter', () => { expect(response.body.metrics).toHaveLength(2); const metricIds = response.body.metrics.map((m: Metric) => m.id); - expect(metricIds).toContain('github.open_prs'); - expect(metricIds).toContain('github.open_issues'); + expect(metricIds).toContain('github.openPrs'); + expect(metricIds).toContain('github.openIssues'); }); it('should return 400 InputError when invalid metricIds parameter - empty string', async () => { @@ -254,14 +254,14 @@ describe('createRouter', () => { it('should return only existing metrics when metricIds contains non-existent IDs', async () => { const response = await request(app).get( - '/metrics?metricIds=github.open_prs,non.existent.metric', + '/metrics?metricIds=github.openPrs,non.existent.metric', ); expect(response.status).toBe(200); expect(response.body).toHaveProperty('metrics'); expect(response.body.metrics).toHaveLength(1); - expect(response.body.metrics[0].id).toBe('github.open_prs'); + expect(response.body.metrics[0].id).toBe('github.openPrs'); }); it('should return metrics filtered by datasource', async () => { @@ -272,8 +272,8 @@ describe('createRouter', () => { expect(response.body.metrics).toHaveLength(2); const metricIds = response.body.metrics.map((m: Metric) => m.id); - expect(metricIds).toContain('github.open_prs'); - expect(metricIds).toContain('github.open_issues'); + expect(metricIds).toContain('github.openPrs'); + expect(metricIds).toContain('github.openIssues'); }); it('should return metrics filtered by datasource - sonar', async () => { @@ -321,7 +321,7 @@ describe('createRouter', () => { describe('GET /metrics/catalog/:kind/:namespace/:name', () => { const mockMetricResults: MetricResult[] = [ { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: githubNumberMetricMetadata, result: { @@ -341,7 +341,7 @@ describe('createRouter', () => { }, }, { - id: 'github.open_issues', + id: 'github.openIssues', status: 'success', metadata: githubNumberMetricMetadata, result: { @@ -409,13 +409,13 @@ describe('createRouter', () => { it('should handle multiple metricIds parameter', async () => { const response = await request(app).get( - '/metrics/catalog/component/default/my-service?metricIds=github.open_prs,github.open_issues', + '/metrics/catalog/component/default/my-service?metricIds=github.openPrs,github.openIssues', ); expect(response.status).toBe(200); expect(catalogMetricService.getLatestEntityMetrics).toHaveBeenCalledWith( 'component:default/my-service', - ['github.open_prs', 'github.open_issues'], + ['github.openPrs', 'github.openIssues'], undefined, ); expect(response.body).toEqual(mockMetricResults); @@ -441,13 +441,13 @@ describe('createRouter', () => { it('should handle single metricIds parameter', async () => { const response = await request(app).get( - '/metrics/catalog/component/default/my-service?metricIds=github.open_prs', + '/metrics/catalog/component/default/my-service?metricIds=github.openPrs', ); expect(response.status).toBe(200); expect(catalogMetricService.getLatestEntityMetrics).toHaveBeenCalledWith( 'component:default/my-service', - ['github.open_prs'], + ['github.openPrs'], undefined, ); }); @@ -469,7 +469,7 @@ describe('createRouter', () => { { rule: 'HAS_METRIC_ID', resourceType: 'scorecard-metric', - params: { metricIds: ['github.open_prs', 'github.open_issues'] }, + params: { metricIds: ['github.openPrs', 'github.openIssues'] }, }, ], }, @@ -517,7 +517,7 @@ describe('createRouter', () => { }; const mockAggregatedMetricResult: AggregatedMetricResult = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub Open PRs', @@ -547,7 +547,7 @@ describe('createRouter', () => { }; const mockDbAggregatedMetric: DbAggregatedMetric = { - metric_id: 'github.open_prs', + metric_id: 'github.openPrs', total: 12, max_timestamp: new Date('2025-01-01T10:30:00.000Z'), statusCounts: { @@ -568,12 +568,12 @@ describe('createRouter', () => { beforeEach(async () => { const githubProvider = new MockNumberProvider( - 'github.open_prs', + 'github.openPrs', 'github', 'GitHub Open PRs', ); const jiraProvider = new MockNumberProvider( - 'jira.open_issues', + 'jira.openIssues', 'jira', 'Jira Open Issues', ); @@ -644,14 +644,14 @@ describe('createRouter', () => { { result: AuthorizeResult.DENY }, ]); const result = await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(result.statusCode).toBe(403); expect(result.body.error.name).toEqual('NotAllowedError'); expect(result.headers.deprecation).toBe('true'); expect(result.headers.link).toBe( - '; rel="alternate"', + '; rel="alternate"', ); }); @@ -660,7 +660,7 @@ describe('createRouter', () => { principal: {}, } as any); const result = await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(result.statusCode).toBe(401); @@ -675,7 +675,7 @@ describe('createRouter', () => { CONDITIONAL_POLICY_DECISION, ]); const result = await request(aggregationApp).get( - '/metrics/jira.open_issues/catalog/aggregations', + '/metrics/jira.openIssues/catalog/aggregations', ); expect(result.statusCode).toBe(403); @@ -699,20 +699,20 @@ describe('createRouter', () => { it('should return aggregated metrics for a specific metric', async () => { const response = await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(response.status).toBe(200); expect(response.body).toEqual(mockAggregatedMetricResult); expect(response.headers.deprecation).toBe('true'); expect(response.headers.link).toBe( - '; rel="alternate"', + '; rel="alternate"', ); }); it('should call authorizeConditional to check permissions', async () => { await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(permissionsMock.authorizeConditional).toHaveBeenCalledTimes(1); @@ -720,7 +720,7 @@ describe('createRouter', () => { it('should call getEntitiesOwnedByUser to get entities owned by user', async () => { await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(getEntitiesOwnedByUserSpy).toHaveBeenCalledTimes(1); @@ -737,7 +737,7 @@ describe('createRouter', () => { const emptyAggregatedMetric = AggregatedMetricMapper.toAggregatedMetric(); const { AggregatedMetricMapper: ActualAggregatedMetricMapper } = jest.requireActual('./mappers'); - const provider = metricProvidersRegistry.getProvider('github.open_prs'); + const provider = metricProvidersRegistry.getProvider('github.openPrs'); const thresholds = provider.getMetricThresholds(); const emptyAggregatedMetricResult = ActualAggregatedMetricMapper.toAggregatedMetricResult( @@ -754,11 +754,11 @@ describe('createRouter', () => { calculationErrorCount: 0, }, { - id: 'github.open_prs', + id: 'github.openPrs', title: 'GitHub Open PRs', description: 'Mock number description.', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, ); @@ -768,7 +768,7 @@ describe('createRouter', () => { ); const response = await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(response.status).toBe(200); @@ -780,19 +780,19 @@ describe('createRouter', () => { it('should call readAggregatedMetricByEntityRefs to get aggregated metric', async () => { await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(readAggregatedMetricByEntityRefsSpy).toHaveBeenCalledTimes(1); expect(readAggregatedMetricByEntityRefsSpy).toHaveBeenCalledWith( ['component:default/my-service', 'component:default/my-other-service'], - 'github.open_prs', + 'github.openPrs', ); }); it('should check entity access for each entity owned by user', async () => { await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(checkEntityAccessSpy).toHaveBeenCalledTimes(2); @@ -812,20 +812,20 @@ describe('createRouter', () => { it('should call toAggregatedMetricResult to map aggregated data to the API result', async () => { await request(aggregationApp).get( - '/metrics/github.open_prs/catalog/aggregations', + '/metrics/github.openPrs/catalog/aggregations', ); expect(toAggregatedMetricResultSpy).toHaveBeenCalledTimes(1); expect(toAggregatedMetricResultSpy).toHaveBeenCalledWith( - metricProvidersRegistry.getMetric('github.open_prs'), + metricProvidersRegistry.getMetric('github.openPrs'), expect.objectContaining({ total: mockAggregatedMetric.total, timestamp: mockAggregatedMetric.timestamp, }), expect.objectContaining({ - id: 'github.open_prs', + id: 'github.openPrs', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }), ); }); @@ -895,7 +895,7 @@ describe('createRouter', () => { }; const mockAggregatedMetricResult: AggregatedMetricResult = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub Open PRs', @@ -925,7 +925,7 @@ describe('createRouter', () => { }; const mockDbAggregatedMetricForAgId: DbAggregatedMetric = { - metric_id: 'github.open_prs', + metric_id: 'github.openPrs', total: 6, max_timestamp: new Date('2025-01-01T10:30:00.000Z'), statusCounts: { @@ -946,10 +946,10 @@ describe('createRouter', () => { beforeEach(async () => { metricRegistry = new MetricProvidersRegistry(); metricRegistry.register( - new MockNumberProvider('github.open_prs', 'github', 'GitHub Open PRs'), + new MockNumberProvider('github.openPrs', 'github', 'GitHub Open PRs'), ); metricRegistry.register( - new MockNumberProvider('jira.open_issues', 'jira', 'Jira Open Issues'), + new MockNumberProvider('jira.openIssues', 'jira', 'Jira Open Issues'), ); mockCatalog = catalogServiceMock.mock(); @@ -1029,7 +1029,7 @@ describe('createRouter', () => { it('should return 200 with correct response body', async () => { const response = await request(aggregationsApp).get( - '/aggregations/github.open_prs', + '/aggregations/github.openPrs', ); expect(response.status).toBe(200); @@ -1039,11 +1039,11 @@ describe('createRouter', () => { }); it('should call readAggregatedMetricByEntityRefs when no KPI config', async () => { - await request(aggregationsApp).get('/aggregations/github.open_prs'); + await request(aggregationsApp).get('/aggregations/github.openPrs'); expect(readAggregatedMetricByEntityRefsSpyAgId).toHaveBeenCalledWith( ['component:default/my-service', 'component:default/my-other-service'], - 'github.open_prs', + 'github.openPrs', ); }); @@ -1053,7 +1053,7 @@ describe('createRouter', () => { ]); const response = await request(aggregationsApp).get( - '/aggregations/github.open_prs', + '/aggregations/github.openPrs', ); expect(response.status).toBe(403); @@ -1066,7 +1066,7 @@ describe('createRouter', () => { } as any); const response = await request(aggregationsApp).get( - '/aggregations/github.open_prs', + '/aggregations/github.openPrs', ); expect(response.status).toBe(401); @@ -1136,7 +1136,7 @@ describe('createRouter', () => { title: 'Custom KPI title', description: 'Custom KPI description', type: 'statusGrouped', - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -1183,7 +1183,7 @@ describe('createRouter', () => { expect(getSpy).toHaveBeenCalledWith( ['component:default/my-service', 'component:default/my-other-service'], - 'github.open_prs', + 'github.openPrs', ); }); @@ -1195,7 +1195,7 @@ describe('createRouter', () => { title: 'Weighted health KPI', description: 'Weighted average', type: 'average', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { error: 0, @@ -1249,7 +1249,7 @@ describe('createRouter', () => { expect(getSpy).toHaveBeenCalledWith( ['component:default/my-service', 'component:default/my-other-service'], - 'github.open_prs', + 'github.openPrs', ); }); }); @@ -1263,7 +1263,7 @@ describe('createRouter', () => { beforeEach(async () => { metaRegistry = new MetricProvidersRegistry(); metaRegistry.register( - new MockNumberProvider('github.open_prs', 'github', 'GitHub Open PRs'), + new MockNumberProvider('github.openPrs', 'github', 'GitHub Open PRs'), ); metaCatalog = catalogServiceMock.mock(); @@ -1275,7 +1275,7 @@ describe('createRouter', () => { title: 'Custom KPI title', description: 'Custom KPI description', type: 'statusGrouped', - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -1406,7 +1406,7 @@ describe('createRouter', () => { svcApp.use(mockErrorHandler()); const response = await request(svcApp).get( - '/aggregations/github.open_prs/metadata', + '/aggregations/github.openPrs/metadata', ); expect(response.status).toBe(200); @@ -1417,7 +1417,7 @@ describe('createRouter', () => { describe('GET /metrics/:metricId/catalog/aggregations/entities', () => { const mockEntityMetricDetailResponse = { - metricId: 'github.open_prs', + metricId: 'github.openPrs', metricMetadata: { title: 'GitHub Open PRs', description: 'Mock number description.', @@ -1463,14 +1463,14 @@ describe('createRouter', () => { beforeEach(async () => { const githubProvider = new MockNumberProvider( - 'github.open_prs', + 'github.openPrs', 'github', 'GitHub Open PRs', ); metricProvidersRegistry.register(githubProvider); const jiraProvider = new MockNumberProvider( - 'jira.open_issues', + 'jira.openIssues', 'jira', 'Jira Open Issues', ); @@ -1507,13 +1507,13 @@ describe('createRouter', () => { it('should return entity metric details with default pagination', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities', + '/metrics/github.openPrs/catalog/aggregations/entities', ); expect(response.status).toBe(200); expect(response.body).toEqual(mockEntityMetricDetailResponse); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, { status: undefined, @@ -1530,11 +1530,11 @@ describe('createRouter', () => { it('should handle custom page and pageSize', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?page=2&pageSize=20', + '/metrics/github.openPrs/catalog/aggregations/entities?page=2&pageSize=20', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ page: 2, @@ -1545,7 +1545,7 @@ describe('createRouter', () => { it('should return 400 when pageSize exceeds max of 100', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?pageSize=200', + '/metrics/github.openPrs/catalog/aggregations/entities?pageSize=200', ); expect(response.status).toBe(400); @@ -1556,12 +1556,12 @@ describe('createRouter', () => { it('should accept pageSize at max boundary of 100', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?pageSize=100', + '/metrics/github.openPrs/catalog/aggregations/entities?pageSize=100', ); expect(response.status).toBe(200); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ limit: 100, @@ -1571,11 +1571,11 @@ describe('createRouter', () => { it('should filter by status', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?status=error', + '/metrics/github.openPrs/catalog/aggregations/entities?status=error', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ status: 'error', @@ -1585,11 +1585,11 @@ describe('createRouter', () => { it('should filter by owner', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?owner=team:default/platform', + '/metrics/github.openPrs/catalog/aggregations/entities?owner=team:default/platform', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ owner: ['team:default/platform'], @@ -1599,11 +1599,11 @@ describe('createRouter', () => { it('should filter by kind', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?kind=Component', + '/metrics/github.openPrs/catalog/aggregations/entities?kind=Component', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ kind: 'Component', @@ -1613,11 +1613,11 @@ describe('createRouter', () => { it('should filter by entityName', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?entityName=service', + '/metrics/github.openPrs/catalog/aggregations/entities?entityName=service', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ entityName: 'service', @@ -1627,11 +1627,11 @@ describe('createRouter', () => { it('should sort by entityName ascending', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?sortBy=entityName&sortOrder=asc', + '/metrics/github.openPrs/catalog/aggregations/entities?sortBy=entityName&sortOrder=asc', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ sortBy: 'entityName', @@ -1642,11 +1642,11 @@ describe('createRouter', () => { it('should sort by metricValue descending', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?sortBy=metricValue&sortOrder=desc', + '/metrics/github.openPrs/catalog/aggregations/entities?sortBy=metricValue&sortOrder=desc', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ sortBy: 'metricValue', @@ -1657,11 +1657,11 @@ describe('createRouter', () => { it('should combine multiple filters', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?status=error&kind=Component&owner=team:default/platform&sortBy=metricValue&sortOrder=desc', + '/metrics/github.openPrs/catalog/aggregations/entities?status=error&kind=Component&owner=team:default/platform&sortBy=metricValue&sortOrder=desc', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ status: 'error', @@ -1679,7 +1679,7 @@ describe('createRouter', () => { ]); const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities', + '/metrics/github.openPrs/catalog/aggregations/entities', ); expect(response.status).toBe(403); @@ -1692,7 +1692,7 @@ describe('createRouter', () => { } as any); const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities', + '/metrics/github.openPrs/catalog/aggregations/entities', ); expect(response.status).toBe(401); @@ -1708,7 +1708,7 @@ describe('createRouter', () => { ]); const response = await request(drillDownApp).get( - '/metrics/jira.open_issues/catalog/aggregations/entities', + '/metrics/jira.openIssues/catalog/aggregations/entities', ); expect(response.status).toBe(403); @@ -1726,7 +1726,7 @@ describe('createRouter', () => { it('should return empty entities array when no results', async () => { getEntityMetricDetailsSpy.mockResolvedValue({ - metricId: 'github.open_prs', + metricId: 'github.openPrs', metricMetadata: mockEntityMetricDetailResponse.metricMetadata, entities: [], pagination: { @@ -1744,7 +1744,7 @@ describe('createRouter', () => { }); const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities', + '/metrics/github.openPrs/catalog/aggregations/entities', ); expect(response.status).toBe(200); @@ -1754,11 +1754,11 @@ describe('createRouter', () => { it('should normalize multi-value owner params to an array', async () => { await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?owner=team:default/platform&owner=user:default/alice', + '/metrics/github.openPrs/catalog/aggregations/entities?owner=team:default/platform&owner=user:default/alice', ); expect(getEntityMetricDetailsSpy).toHaveBeenCalledWith( - 'github.open_prs', + 'github.openPrs', mockCredentials, expect.objectContaining({ owner: ['team:default/platform', 'user:default/alice'], @@ -1769,7 +1769,7 @@ describe('createRouter', () => { describe('input validation', () => { it('should return 400 when page is 0', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?page=0', + '/metrics/github.openPrs/catalog/aggregations/entities?page=0', ); expect(response.status).toBe(400); @@ -1782,7 +1782,7 @@ describe('createRouter', () => { it('should return 400 when page is negative', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?page=-1', + '/metrics/github.openPrs/catalog/aggregations/entities?page=-1', ); expect(response.status).toBe(400); @@ -1795,7 +1795,7 @@ describe('createRouter', () => { it('should return 400 when page exceeds max of 10000', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?page=10001', + '/metrics/github.openPrs/catalog/aggregations/entities?page=10001', ); expect(response.status).toBe(400); @@ -1808,7 +1808,7 @@ describe('createRouter', () => { it('should return 400 when pageSize is 0', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?pageSize=0', + '/metrics/github.openPrs/catalog/aggregations/entities?pageSize=0', ); expect(response.status).toBe(400); @@ -1821,7 +1821,7 @@ describe('createRouter', () => { it('should return 400 when status is an empty string', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?status=', + '/metrics/github.openPrs/catalog/aggregations/entities?status=', ); expect(response.status).toBe(400); @@ -1834,7 +1834,7 @@ describe('createRouter', () => { it('should return 400 when sortBy is an invalid value', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?sortBy=invalid', + '/metrics/github.openPrs/catalog/aggregations/entities?sortBy=invalid', ); expect(response.status).toBe(400); @@ -1847,7 +1847,7 @@ describe('createRouter', () => { it('should return 400 when sortOrder is an invalid value', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?sortOrder=random', + '/metrics/github.openPrs/catalog/aggregations/entities?sortOrder=random', ); expect(response.status).toBe(400); @@ -1860,7 +1860,7 @@ describe('createRouter', () => { it('should return 400 when owner is an empty string', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?owner=', + '/metrics/github.openPrs/catalog/aggregations/entities?owner=', ); expect(response.status).toBe(400); @@ -1873,7 +1873,7 @@ describe('createRouter', () => { it('should return 400 when kind is an empty string', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?kind=', + '/metrics/github.openPrs/catalog/aggregations/entities?kind=', ); expect(response.status).toBe(400); @@ -1886,7 +1886,7 @@ describe('createRouter', () => { it('should return 400 when entityName is an empty string', async () => { const response = await request(drillDownApp).get( - '/metrics/github.open_prs/catalog/aggregations/entities?entityName=', + '/metrics/github.openPrs/catalog/aggregations/entities?entityName=', ); expect(response.status).toBe(400); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.test.ts index f2fd498e0a..32abb934b6 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.test.ts @@ -27,7 +27,7 @@ describe('ThresholdResolver', () => { scorecard: { plugins: { github: { - number_metric: { + numberMetric: { thresholds: { rules: [ { key: 'error', expression: '>100' }, @@ -42,7 +42,7 @@ describe('ThresholdResolver', () => { }; it('uses default provider thresholds when no custom thresholds', () => { - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver( new ConfigReader({ scorecard: { @@ -74,7 +74,7 @@ describe('ThresholdResolver', () => { }); it('uses configured thresholds before provider default thresholds', () => { - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver(new ConfigReader(customThresholds), [ new MockNumberProvider('github.other_metric', 'github'), provider, @@ -138,12 +138,12 @@ describe('ThresholdResolver', () => { }); it('merges entity annotation overrides on top of default provider thresholds', () => { - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver(new ConfigReader({}), [provider]); const entity = new MockEntityBuilder() .withAnnotations({ - 'scorecard.io/github.number_metric.thresholds.rules.warning': '>10', - 'scorecard.io/github.number_metric.thresholds.rules.success': '<=10', + 'scorecard.io/github.numberMetric.thresholds.rules.warning': '>10', + 'scorecard.io/github.numberMetric.thresholds.rules.success': '<=10', }) .build(); @@ -157,12 +157,12 @@ describe('ThresholdResolver', () => { }); it('merges entity annotation overrides on top of default provider thresholds when provider is unexpectedly not loaded on startup', () => { - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver(new ConfigReader({}), []); const entity = new MockEntityBuilder() .withAnnotations({ - 'scorecard.io/github.number_metric.thresholds.rules.warning': '>10', - 'scorecard.io/github.number_metric.thresholds.rules.success': '<=10', + 'scorecard.io/github.numberMetric.thresholds.rules.warning': '>10', + 'scorecard.io/github.numberMetric.thresholds.rules.success': '<=10', }) .build(); @@ -176,14 +176,14 @@ describe('ThresholdResolver', () => { }); it('merges entity annotation overrides on top of custom provider thresholds', () => { - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver(new ConfigReader(customThresholds), [ provider, ]); const entity = new MockEntityBuilder() .withAnnotations({ - 'scorecard.io/github.number_metric.thresholds.rules.warning': '>10', - 'scorecard.io/github.number_metric.thresholds.rules.success': '<=10', + 'scorecard.io/github.numberMetric.thresholds.rules.warning': '>10', + 'scorecard.io/github.numberMetric.thresholds.rules.success': '<=10', }) .build(); @@ -226,7 +226,7 @@ describe('ThresholdResolver', () => { ], }), } as any; - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); const resolver = new ThresholdResolver(mockConfig, [provider]); resolver.resolveProviderThresholds(provider); @@ -241,10 +241,10 @@ describe('ThresholdResolver', () => { rules: [{ key: 'error', expression: 'INVALID' }], }), } as any; - const provider = new MockNumberProvider('github.number_metric', 'github'); + const provider = new MockNumberProvider('github.numberMetric', 'github'); expect(() => new ThresholdResolver(mockConfig, [provider])).toThrow( - 'Invalid thresholds configuration at scorecard.plugins.github.number_metric.thresholds', + 'Invalid thresholds configuration at scorecard.plugins.github.numberMetric.thresholds', ); }); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/utils/buildAggregationConfig.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/utils/buildAggregationConfig.test.ts index 5b977cb335..21cbc9af5f 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/utils/buildAggregationConfig.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/utils/buildAggregationConfig.test.ts @@ -24,7 +24,7 @@ describe('buildAggregationConfig', () => { title: 'GitHub PRs', description: 'Open pull requests', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }); const result = buildAggregationConfig('openPrsKpi', { config }); @@ -34,7 +34,7 @@ describe('buildAggregationConfig', () => { title: 'GitHub PRs', description: 'Open pull requests', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }); }); @@ -43,7 +43,7 @@ describe('buildAggregationConfig', () => { title: 'Weighted health', description: 'Average across statuses', type: aggregationTypes.average, - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { error: 0, @@ -60,7 +60,7 @@ describe('buildAggregationConfig', () => { title: 'Weighted health', description: 'Average across statuses', type: aggregationTypes.average, - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { error: 0, warning: 50, success: 100 }, }, @@ -73,7 +73,7 @@ describe('buildAggregationConfig', () => { title: 'Weighted health', description: 'Average across statuses', type: aggregationTypes.average, - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { success: 100, warning: 50, error: 0 }, thresholds: { diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts index e132434ff0..20b8565c76 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts @@ -41,11 +41,11 @@ describe('mergeEntityAndProviderThresholds', () => { let entity: Entity; const numberMetricProvider = new MockNumberProvider( - 'github.important_metric', + 'github.importantMetric', 'github', ); const booleanMetricProvider = new MockBooleanProvider( - 'jira.boolean_metric', + 'jira.booleanMetric', 'jira', ); @@ -104,7 +104,7 @@ describe('mergeEntityAndProviderThresholds', () => { describe('when entity has valid threshold overrides', () => { it('should override single provider threshold rule for number metric', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.error': '>50', + 'scorecard.io/github.importantMetric.thresholds.rules.error': '>50', }; const result = mergeEntityAndProviderThresholds( entity, @@ -122,9 +122,9 @@ describe('mergeEntityAndProviderThresholds', () => { it('should override multiple provider threshold rules for number metric', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.error': '>50', - 'scorecard.io/github.important_metric.thresholds.rules.warning': '>30', - 'scorecard.io/github.important_metric.thresholds.rules.success': '<=30', + 'scorecard.io/github.importantMetric.thresholds.rules.error': '>50', + 'scorecard.io/github.importantMetric.thresholds.rules.warning': '>30', + 'scorecard.io/github.importantMetric.thresholds.rules.success': '<=30', }; const result = mergeEntityAndProviderThresholds( entity, @@ -142,7 +142,7 @@ describe('mergeEntityAndProviderThresholds', () => { it('should override provider threshold rule for boolean metric', () => { entity.metadata.annotations = { - 'scorecard.io/jira.boolean_metric.thresholds.rules.success': '!=false', + 'scorecard.io/jira.booleanMetric.thresholds.rules.success': '!=false', }; const result = mergeEntityAndProviderThresholds( entity, @@ -159,7 +159,7 @@ describe('mergeEntityAndProviderThresholds', () => { it('should ignore annotations with empty expression values', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.error': '', + 'scorecard.io/github.importantMetric.thresholds.rules.error': '', }; const result = mergeEntityAndProviderThresholds( entity, @@ -172,8 +172,8 @@ describe('mergeEntityAndProviderThresholds', () => { it('should ignore annotations that do not match the provider prefix', () => { entity.metadata.annotations = { 'scorecard.io/other.provider.thresholds.rules.error': '>50', - 'scorecard.io/github.important_metric.thresholds.rules.warning': '>30', - 'scorecard.io/github.important_metric.thresholds.rules.success': '<=30', + 'scorecard.io/github.importantMetric.thresholds.rules.warning': '>30', + 'scorecard.io/github.importantMetric.thresholds.rules.success': '<=30', }; const result = mergeEntityAndProviderThresholds( entity, @@ -191,10 +191,9 @@ describe('mergeEntityAndProviderThresholds', () => { it('should handle range expressions in overrides', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.error': '>100', - 'scorecard.io/github.important_metric.thresholds.rules.warning': - '0-100', - 'scorecard.io/github.important_metric.thresholds.rules.success': '<0', + 'scorecard.io/github.importantMetric.thresholds.rules.error': '>100', + 'scorecard.io/github.importantMetric.thresholds.rules.warning': '0-100', + 'scorecard.io/github.importantMetric.thresholds.rules.success': '<0', }; const result = mergeEntityAndProviderThresholds( entity, @@ -286,7 +285,7 @@ describe('mergeEntityAndProviderThresholds', () => { it('should throw error for invalid threshold expression', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.error': 'invalid', + 'scorecard.io/github.importantMetric.thresholds.rules.error': 'invalid', }; expect(() => mergeEntityAndProviderThresholds(entity, numberMetricProvider), @@ -294,13 +293,13 @@ describe('mergeEntityAndProviderThresholds', () => { expect(() => mergeEntityAndProviderThresholds(entity, numberMetricProvider), ).toThrow( - "Invalid threshold annotation 'scorecard.io/github.important_metric.thresholds.rules.error: invalid' in entity 'component:default/test-component'", + "Invalid threshold annotation 'scorecard.io/github.importantMetric.thresholds.rules.error: invalid' in entity 'component:default/test-component'", ); }); it('should throw ThresholdConfigFormatError with annotation path when boolean override expression is invalid', () => { entity.metadata.annotations = { - 'scorecard.io/jira.boolean_metric.thresholds.rules.success': '>40', + 'scorecard.io/jira.booleanMetric.thresholds.rules.success': '>40', }; expect(() => mergeEntityAndProviderThresholds(entity, booleanMetricProvider), @@ -308,14 +307,14 @@ describe('mergeEntityAndProviderThresholds', () => { expect(() => mergeEntityAndProviderThresholds(entity, booleanMetricProvider), ).toThrow( - "Invalid threshold annotation 'scorecard.io/jira.boolean_metric.thresholds.rules.success: >40' in entity 'component:default/test-component'", + "Invalid threshold annotation 'scorecard.io/jira.booleanMetric.thresholds.rules.success: >40' in entity 'component:default/test-component'", ); }); it('should preserve order of provider rules when overriding', () => { entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.success': '<=20', - 'scorecard.io/github.important_metric.thresholds.rules.error': '>50', + 'scorecard.io/github.importantMetric.thresholds.rules.success': '<=20', + 'scorecard.io/github.importantMetric.thresholds.rules.error': '>50', }; const result = mergeEntityAndProviderThresholds( entity, @@ -344,12 +343,9 @@ describe('mergeEntityAndProviderThresholds', () => { }; } } - const mockedProvider = new MockProvider( - 'github.important_metric', - 'github', - ); + const mockedProvider = new MockProvider('github.importantMetric', 'github'); entity.metadata.annotations = { - 'scorecard.io/github.important_metric.thresholds.rules.success': '<=10', + 'scorecard.io/github.importantMetric.thresholds.rules.success': '<=10', }; expect(() => mergeEntityAndProviderThresholds(entity, mockedProvider), @@ -357,7 +353,7 @@ describe('mergeEntityAndProviderThresholds', () => { expect(() => mergeEntityAndProviderThresholds(entity, mockedProvider), ).toThrow( - 'Unable to override component:default/test-component thresholds by {"key":"success","expression":"<=10"}, metric provider github.important_metric does not support key success', + 'Unable to override component:default/test-component thresholds by {"key":"success","expression":"<=10"}, metric provider github.importantMetric does not support key success', ); }); }); diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/utils/parseCommaSeparatedString.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/utils/parseCommaSeparatedString.test.ts index 83d6cdb8a6..75ed0be444 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/utils/parseCommaSeparatedString.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/utils/parseCommaSeparatedString.test.ts @@ -18,16 +18,16 @@ import { parseCommaSeparatedString } from './parseCommaSeparatedString'; describe('parseCommaSeparatedString', () => { it('should return array with single value for non-comma string', () => { - const result = parseCommaSeparatedString('github.open_prs'); - expect(result).toEqual(['github.open_prs']); + const result = parseCommaSeparatedString('github.openPrs'); + expect(result).toEqual(['github.openPrs']); }); it('should return array with trimmed whitespace multiple values when values are comma and space separated', () => { const result = parseCommaSeparatedString( - ' github.open_prs , github.open_issues ', + ' github.openPrs , github.openIssues ', ); - expect(result).toEqual(['github.open_prs', 'github.open_issues']); + expect(result).toEqual(['github.openPrs', 'github.openIssues']); }); it('should handle string with only whitespace', () => { diff --git a/workspaces/scorecard/plugins/scorecard-backend/src/validation/validateAggregationConfig.test.ts b/workspaces/scorecard/plugins/scorecard-backend/src/validation/validateAggregationConfig.test.ts index 951c39d3a1..85599de3e0 100644 --- a/workspaces/scorecard/plugins/scorecard-backend/src/validation/validateAggregationConfig.test.ts +++ b/workspaces/scorecard/plugins/scorecard-backend/src/validation/validateAggregationConfig.test.ts @@ -34,7 +34,7 @@ describe('validateAggregationConfig', () => { it('should not throw when all KPI entries are valid and metrics are registered', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -43,7 +43,7 @@ describe('validateAggregationConfig', () => { title: 'GitHub PRs', description: 'Open pull requests', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -56,7 +56,7 @@ describe('validateAggregationConfig', () => { it('should throw InputError when a KPI entry fails schema validation', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const tooLong = 'a'.repeat(256); const rootConfig = new ConfigReader({ @@ -66,7 +66,7 @@ describe('validateAggregationConfig', () => { title: tooLong, description: 'Valid description', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -79,7 +79,7 @@ describe('validateAggregationConfig', () => { it('should throw InputError when aggregation type is invalid', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -88,7 +88,7 @@ describe('validateAggregationConfig', () => { title: 'Valid title', description: 'Valid description', type: 'notARealAggregationType', - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -109,7 +109,7 @@ describe('validateAggregationConfig', () => { title: 'GitHub PRs', description: 'Open pull requests', type: aggregationTypes.statusGrouped, - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -117,14 +117,14 @@ describe('validateAggregationConfig', () => { expect(() => validateAggregationConfig({ rootConfig, registry })).toThrow( new Error( - `Metric provider with ID 'github.open_prs' is not registered (${AGGREGATION_KPIS_CONFIG_PATH}.openPrsKpi).`, + `Metric provider with ID 'github.openPrs' is not registered (${AGGREGATION_KPIS_CONFIG_PATH}.openPrsKpi).`, ), ); }); it('should not throw when average KPI has options.statusScores (app-config shape)', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -133,7 +133,7 @@ describe('validateAggregationConfig', () => { title: 'GitHub Open PRs (weighted health)', type: aggregationTypes.average, description: 'Weighted health average for open PRs.', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { success: 100, @@ -153,7 +153,7 @@ describe('validateAggregationConfig', () => { it('should throw when type is average but required options block is missing', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -162,7 +162,7 @@ describe('validateAggregationConfig', () => { title: 'Avg KPI', type: aggregationTypes.average, description: 'Weighted health', - metricId: 'github.open_prs', + metricId: 'github.openPrs', }, }, }, @@ -175,7 +175,7 @@ describe('validateAggregationConfig', () => { it('should throw InputError when type is average but options.statusScores is empty', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -184,7 +184,7 @@ describe('validateAggregationConfig', () => { title: 'Avg KPI', type: aggregationTypes.average, description: 'Weighted health', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: {} }, }, }, @@ -198,7 +198,7 @@ describe('validateAggregationConfig', () => { it('should not throw when average KPI includes optional thresholds', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -207,7 +207,7 @@ describe('validateAggregationConfig', () => { title: 'Avg KPI', type: aggregationTypes.average, description: 'Weighted health', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { success: 100, warning: 50, error: 0 }, thresholds: { @@ -238,7 +238,7 @@ describe('validateAggregationConfig', () => { it('should throw when thresholds has an invalid expression', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -247,7 +247,7 @@ describe('validateAggregationConfig', () => { title: 'Avg KPI', type: aggregationTypes.average, description: 'Weighted health', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { success: 100, warning: 50, error: 0 }, thresholds: { @@ -272,7 +272,7 @@ describe('validateAggregationConfig', () => { it('should throw when average KPI thresholds leave a gap on the number line', () => { const registry = new MetricProvidersRegistry(); - registry.register(new MockNumberProvider('github.open_prs', 'github')); + registry.register(new MockNumberProvider('github.openPrs', 'github')); const rootConfig = new ConfigReader({ scorecard: { @@ -281,7 +281,7 @@ describe('validateAggregationConfig', () => { title: 'Avg KPI', type: aggregationTypes.average, description: 'Weighted health', - metricId: 'github.open_prs', + metricId: 'github.openPrs', options: { statusScores: { success: 100, warning: 50, error: 0 }, thresholds: { diff --git a/workspaces/scorecard/plugins/scorecard/README.md b/workspaces/scorecard/plugins/scorecard/README.md index 5356935f61..f30c454674 100644 --- a/workspaces/scorecard/plugins/scorecard/README.md +++ b/workspaces/scorecard/plugins/scorecard/README.md @@ -296,10 +296,10 @@ The following modules and extensions are available from `@red-hat-developer-hub/ import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard'; // GitHub open PRs - + // Jira open issues - + ``` 4. Ensure the frontend can reach the Scorecard backend by configuring discovery in `app-config.yaml` (see discovery snippet under [NFS](#nfs-new-frontend-system--app)). @@ -380,7 +380,7 @@ import { ComponentType } from 'react'; layouts: { /* … */ }, props: { aggregationId: 'openIssuesKpi', - // metricId: 'jira.open_issues', // legacy only; remove when only aggregationId is supported + // metricId: 'jira.openIssues', // legacy only; remove when only aggregationId is supported }, }, }, @@ -448,7 +448,7 @@ If a translation key is not found, the plugin will automatically fall back to: ```typescript // In ref.ts metric: { - 'github.open_prs': { + 'github.openPrs': { title: 'GitHub open PRs', description: 'Current count of open Pull Requests for a given GitHub repository', }, diff --git a/workspaces/scorecard/plugins/scorecard/__fixtures__/scorecardData.ts b/workspaces/scorecard/plugins/scorecard/__fixtures__/scorecardData.ts index f33f6da963..e68b793481 100644 --- a/workspaces/scorecard/plugins/scorecard/__fixtures__/scorecardData.ts +++ b/workspaces/scorecard/plugins/scorecard/__fixtures__/scorecardData.ts @@ -23,7 +23,7 @@ import { export const mockScorecardSuccessData = [ { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success' as const, metadata: { title: 'GitHub open PRs', @@ -49,7 +49,7 @@ export const mockScorecardSuccessData = [ }, }, { - id: 'jira.open_issues', + id: 'jira.openIssues', status: 'success' as const, metadata: { title: 'Jira open blocking tickets', @@ -78,7 +78,7 @@ export const mockScorecardSuccessData = [ export const mockScorecardErrorData = [ { - id: 'github.open_issues', + id: 'github.openIssues', status: 'error' as const, metadata: { title: 'GitHub open Issues', @@ -105,7 +105,7 @@ export const mockScorecardErrorData = [ error: 'HttpError: API rate limit exceeded.', }, { - id: 'sonar.security_issues', + id: 'sonar.securityIssues', status: 'success' as const, metadata: { title: 'Sonar number of security issues', @@ -127,7 +127,7 @@ export const mockScorecardErrorData = [ evaluation: 'warning', status: 'error' as const, error: - "ThresholdConfigFormatError: Invalid threshold annotation 'scorecard.io/sonar.security_issues.thresholds.rules.error: >- 50' in entity 'component:default/example-service': Invalid threshold expression: >- 50.", + "ThresholdConfigFormatError: Invalid threshold annotation 'scorecard.io/sonar.securityIssues.thresholds.rules.error: >- 50' in entity 'component:default/example-service': Invalid threshold expression: >- 50.", }, }, }, @@ -135,7 +135,7 @@ export const mockScorecardErrorData = [ export const mockAggregatedScorecardData = { [aggregationTypes.statusGrouped]: { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -159,7 +159,7 @@ export const mockAggregatedScorecardData = { }, } as AggregatedMetricResult, [aggregationTypes.average]: { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', diff --git a/workspaces/scorecard/plugins/scorecard/dev/legacy.tsx b/workspaces/scorecard/plugins/scorecard/dev/legacy.tsx index b07c6ad940..40cf0a107f 100644 --- a/workspaces/scorecard/plugins/scorecard/dev/legacy.tsx +++ b/workspaces/scorecard/plugins/scorecard/dev/legacy.tsx @@ -154,7 +154,7 @@ createDevApp() .addPage({ element: ( - + ), title: 'Default Layout', @@ -171,7 +171,7 @@ createDevApp() {label} - + ))} @@ -212,7 +212,7 @@ createDevApp() ), title: 'Scorecard Entities', - path: '/scorecard/aggregations/github.open_prs/metrics/github.open_prs', + path: '/scorecard/aggregations/github.openPrs/metrics/github.openPrs', }) .addPage({ element: ( diff --git a/workspaces/scorecard/plugins/scorecard/report-alpha.api.md b/workspaces/scorecard/plugins/scorecard/report-alpha.api.md index 297dde95a2..465c8c5cec 100644 --- a/workspaces/scorecard/plugins/scorecard/report-alpha.api.md +++ b/workspaces/scorecard/plugins/scorecard/report-alpha.api.md @@ -165,34 +165,34 @@ export const scorecardTranslationRef: TranslationRef< readonly 'errors.noDataFoundMessage': string; readonly 'errors.unsupportedAggregationType': string; readonly 'errors.authenticationErrorMessage': string; - readonly 'metric.github.open_prs.title': string; - readonly 'metric.github.open_prs.description': string; - readonly 'metric.jira.open_issues.title': string; - readonly 'metric.jira.open_issues.description': string; - readonly 'metric.sonarqube.quality_gate.title': string; - readonly 'metric.sonarqube.quality_gate.description': string; - readonly 'metric.sonarqube.open_issues.title': string; - readonly 'metric.sonarqube.open_issues.description': string; - readonly 'metric.sonarqube.security_rating.title': string; - readonly 'metric.sonarqube.security_rating.description': string; - readonly 'metric.sonarqube.security_issues.title': string; - readonly 'metric.sonarqube.security_issues.description': string; - readonly 'metric.sonarqube.security_review_rating.title': string; - readonly 'metric.sonarqube.security_review_rating.description': string; - readonly 'metric.sonarqube.security_hotspots.title': string; - readonly 'metric.sonarqube.security_hotspots.description': string; - readonly 'metric.sonarqube.reliability_rating.title': string; - readonly 'metric.sonarqube.reliability_rating.description': string; - readonly 'metric.sonarqube.reliability_issues.title': string; - readonly 'metric.sonarqube.reliability_issues.description': string; - readonly 'metric.sonarqube.maintainability_rating.title': string; - readonly 'metric.sonarqube.maintainability_rating.description': string; - readonly 'metric.sonarqube.maintainability_issues.title': string; - readonly 'metric.sonarqube.maintainability_issues.description': string; - readonly 'metric.sonarqube.code_coverage.title': string; - readonly 'metric.sonarqube.code_coverage.description': string; - readonly 'metric.sonarqube.code_duplications.title': string; - readonly 'metric.sonarqube.code_duplications.description': string; + readonly 'metric.github.openPrs.title': string; + readonly 'metric.github.openPrs.description': string; + readonly 'metric.jira.openIssues.title': string; + readonly 'metric.jira.openIssues.description': string; + readonly 'metric.sonarqube.qualityGate.title': string; + readonly 'metric.sonarqube.qualityGate.description': string; + readonly 'metric.sonarqube.openIssues.title': string; + readonly 'metric.sonarqube.openIssues.description': string; + readonly 'metric.sonarqube.securityRating.title': string; + readonly 'metric.sonarqube.securityRating.description': string; + readonly 'metric.sonarqube.securityIssues.title': string; + readonly 'metric.sonarqube.securityIssues.description': string; + readonly 'metric.sonarqube.securityReviewRating.title': string; + readonly 'metric.sonarqube.securityReviewRating.description': string; + readonly 'metric.sonarqube.securityHotspots.title': string; + readonly 'metric.sonarqube.securityHotspots.description': string; + readonly 'metric.sonarqube.reliabilityRating.title': string; + readonly 'metric.sonarqube.reliabilityRating.description': string; + readonly 'metric.sonarqube.reliabilityIssues.title': string; + readonly 'metric.sonarqube.reliabilityIssues.description': string; + readonly 'metric.sonarqube.maintainabilityRating.title': string; + readonly 'metric.sonarqube.maintainabilityRating.description': string; + readonly 'metric.sonarqube.maintainabilityIssues.title': string; + readonly 'metric.sonarqube.maintainabilityIssues.description': string; + readonly 'metric.sonarqube.codeCoverage.title': string; + readonly 'metric.sonarqube.codeCoverage.description': string; + readonly 'metric.sonarqube.codeDuplications.title': string; + readonly 'metric.sonarqube.codeDuplications.description': string; readonly 'metric.filecheck.title': string; readonly 'metric.filecheck.description': string; readonly 'metric.lastUpdated': string; diff --git a/workspaces/scorecard/plugins/scorecard/report.api.md b/workspaces/scorecard/plugins/scorecard/report.api.md index 31909b82b4..409a2789ac 100644 --- a/workspaces/scorecard/plugins/scorecard/report.api.md +++ b/workspaces/scorecard/plugins/scorecard/report.api.md @@ -65,34 +65,34 @@ export const scorecardTranslationRef: TranslationRef< readonly 'errors.noDataFoundMessage': string; readonly 'errors.unsupportedAggregationType': string; readonly 'errors.authenticationErrorMessage': string; - readonly 'metric.github.open_prs.title': string; - readonly 'metric.github.open_prs.description': string; - readonly 'metric.jira.open_issues.title': string; - readonly 'metric.jira.open_issues.description': string; - readonly 'metric.sonarqube.quality_gate.title': string; - readonly 'metric.sonarqube.quality_gate.description': string; - readonly 'metric.sonarqube.open_issues.title': string; - readonly 'metric.sonarqube.open_issues.description': string; - readonly 'metric.sonarqube.security_rating.title': string; - readonly 'metric.sonarqube.security_rating.description': string; - readonly 'metric.sonarqube.security_issues.title': string; - readonly 'metric.sonarqube.security_issues.description': string; - readonly 'metric.sonarqube.security_review_rating.title': string; - readonly 'metric.sonarqube.security_review_rating.description': string; - readonly 'metric.sonarqube.security_hotspots.title': string; - readonly 'metric.sonarqube.security_hotspots.description': string; - readonly 'metric.sonarqube.reliability_rating.title': string; - readonly 'metric.sonarqube.reliability_rating.description': string; - readonly 'metric.sonarqube.reliability_issues.title': string; - readonly 'metric.sonarqube.reliability_issues.description': string; - readonly 'metric.sonarqube.maintainability_rating.title': string; - readonly 'metric.sonarqube.maintainability_rating.description': string; - readonly 'metric.sonarqube.maintainability_issues.title': string; - readonly 'metric.sonarqube.maintainability_issues.description': string; - readonly 'metric.sonarqube.code_coverage.title': string; - readonly 'metric.sonarqube.code_coverage.description': string; - readonly 'metric.sonarqube.code_duplications.title': string; - readonly 'metric.sonarqube.code_duplications.description': string; + readonly 'metric.github.openPrs.title': string; + readonly 'metric.github.openPrs.description': string; + readonly 'metric.jira.openIssues.title': string; + readonly 'metric.jira.openIssues.description': string; + readonly 'metric.sonarqube.qualityGate.title': string; + readonly 'metric.sonarqube.qualityGate.description': string; + readonly 'metric.sonarqube.openIssues.title': string; + readonly 'metric.sonarqube.openIssues.description': string; + readonly 'metric.sonarqube.securityRating.title': string; + readonly 'metric.sonarqube.securityRating.description': string; + readonly 'metric.sonarqube.securityIssues.title': string; + readonly 'metric.sonarqube.securityIssues.description': string; + readonly 'metric.sonarqube.securityReviewRating.title': string; + readonly 'metric.sonarqube.securityReviewRating.description': string; + readonly 'metric.sonarqube.securityHotspots.title': string; + readonly 'metric.sonarqube.securityHotspots.description': string; + readonly 'metric.sonarqube.reliabilityRating.title': string; + readonly 'metric.sonarqube.reliabilityRating.description': string; + readonly 'metric.sonarqube.reliabilityIssues.title': string; + readonly 'metric.sonarqube.reliabilityIssues.description': string; + readonly 'metric.sonarqube.maintainabilityRating.title': string; + readonly 'metric.sonarqube.maintainabilityRating.description': string; + readonly 'metric.sonarqube.maintainabilityIssues.title': string; + readonly 'metric.sonarqube.maintainabilityIssues.description': string; + readonly 'metric.sonarqube.codeCoverage.title': string; + readonly 'metric.sonarqube.codeCoverage.description': string; + readonly 'metric.sonarqube.codeDuplications.title': string; + readonly 'metric.sonarqube.codeDuplications.description': string; readonly 'metric.filecheck.title': string; readonly 'metric.filecheck.description': string; readonly 'metric.lastUpdated': string; diff --git a/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx index 750c5f5174..5f38c89d8e 100644 --- a/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/alpha/extensions/homePageCards.tsx @@ -32,11 +32,11 @@ const defaultCardLayout = { } as const; function AggregatedCardWithDeprecatedMetricIdContent() { - return ; + return ; } function AggregatedCardWithDefaultAggregationContent() { - return ; + return ; } function AggregatedCardWithJiraOpenIssuesContent() { diff --git a/workspaces/scorecard/plugins/scorecard/src/api/ScorecardApiClient.test.ts b/workspaces/scorecard/plugins/scorecard/src/api/ScorecardApiClient.test.ts index 057dbc3c5b..85475ccdf3 100644 --- a/workspaces/scorecard/plugins/scorecard/src/api/ScorecardApiClient.test.ts +++ b/workspaces/scorecard/plugins/scorecard/src/api/ScorecardApiClient.test.ts @@ -54,7 +54,7 @@ describe('ScorecardApiClient', () => { describe('getScorecards', () => { const metricRow: MetricResult = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'Open PRs', diff --git a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageCard.test.tsx b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageCard.test.tsx index cdc730ef66..cb8a27cb0a 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageCard.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageCard.test.tsx @@ -143,7 +143,7 @@ jest.mock('../../../hooks/useTranslation', () => ({ // -------------------- const mockScorecard: AggregatedMetricResult = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', diff --git a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageSection.test.tsx b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageSection.test.tsx index 3a464d7933..15f8e66344 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageSection.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardHomepageSection/__tests__/ScorecardHomepageSection.test.tsx @@ -87,7 +87,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => ( ); const mockScorecard: AggregatedMetricResult = { - id: 'github.open_prs', + id: 'github.openPrs', status: 'success', metadata: { title: 'GitHub open PRs', @@ -131,7 +131,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -150,14 +150,14 @@ describe('ScorecardHomepageCard', () => { }); render( - , + , { wrapper: TestWrapper, }, ); expect(useAggregatedScorecard).toHaveBeenCalledWith({ - aggregationId: 'github.open_prs', + aggregationId: 'github.openPrs', }); }); @@ -206,12 +206,12 @@ describe('ScorecardHomepageCard', () => { error: undefined, }); - render(, { + render(, { wrapper: TestWrapper, }); expect(useAggregatedScorecard).toHaveBeenCalledWith({ - aggregationId: 'github.open_prs', + aggregationId: 'github.openPrs', }); }); @@ -224,7 +224,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -253,7 +253,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -276,7 +276,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -302,7 +302,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -338,7 +338,7 @@ describe('ScorecardHomepageCard', () => { render( , { @@ -367,7 +367,7 @@ describe('ScorecardHomepageCard', () => { render( , { diff --git a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTable.test.tsx b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTable.test.tsx index 4533b50c25..543fe71877 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTable.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTable.test.tsx @@ -172,7 +172,7 @@ describe('EntitiesTable', () => { render( , @@ -186,7 +186,7 @@ describe('EntitiesTable', () => { it('should show title with count when total > 0', () => { render( - + , ); @@ -219,7 +219,7 @@ describe('EntitiesTable', () => { render( - + , ); @@ -235,7 +235,7 @@ describe('EntitiesTable', () => { render( - + , ); @@ -251,7 +251,7 @@ describe('EntitiesTable', () => { render( - + , ); @@ -283,7 +283,7 @@ describe('EntitiesTable', () => { render( - + , ); @@ -294,7 +294,7 @@ describe('EntitiesTable', () => { it('should render EntitiesRow for each entity when data is loaded', () => { render( - + , ); @@ -339,7 +339,7 @@ describe('EntitiesTable', () => { render( , diff --git a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTableStateRow.test.tsx b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTableStateRow.test.tsx index b9a801b7f0..6d8afff7cd 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTableStateRow.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/EntitiesTable/__tests__/EntitiesTableStateRow.test.tsx @@ -62,7 +62,7 @@ describe('EntitiesTableStateRow', () => { beforeEach(() => { jest.clearAllMocks(); mockUseMetric.mockReturnValue({ - metric: { id: 'github.open_prs', title: 'Open PRs' }, + metric: { id: 'github.openPrs', title: 'Open PRs' }, }); mockUseMetricDisplayLabels.mockReturnValue({ title: 'Open PRs', @@ -104,7 +104,7 @@ describe('EntitiesTableStateRow', () => { , diff --git a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/__tests__/ScorecardPage.test.tsx b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/__tests__/ScorecardPage.test.tsx index 6fe1b7524d..834627868c 100644 --- a/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/__tests__/ScorecardPage.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/components/ScorecardPage/__tests__/ScorecardPage.test.tsx @@ -103,8 +103,8 @@ describe('ScorecardPage', () => { it('should render page structure with header, content, table and scorecard card', () => { mockUseParams.mockReturnValue({ - aggregationId: 'github.open_prs', - metricId: 'github.open_prs', + aggregationId: 'github.openPrs', + metricId: 'github.openPrs', }); render(, { wrapper: TestWrapper }); @@ -118,14 +118,14 @@ describe('ScorecardPage', () => { it('should pass metricId to header when metricTitle is empty', () => { mockUseParams.mockReturnValue({ - aggregationId: 'github.open_prs', - metricId: 'github.open_prs', + aggregationId: 'github.openPrs', + metricId: 'github.openPrs', }); render(, { wrapper: TestWrapper }); expect(mockScorecardPageHeader).toHaveBeenCalledWith( - expect.objectContaining({ title: 'github.open_prs' }), + expect.objectContaining({ title: 'github.openPrs' }), ); }); @@ -173,15 +173,15 @@ describe('ScorecardPage', () => { it('should pass aggregationId and metricId to ScorecardHomepageCard', () => { mockUseParams.mockReturnValue({ - aggregationId: 'github.open_prs', - metricId: 'github.open_prs', + aggregationId: 'github.openPrs', + metricId: 'github.openPrs', }); render(, { wrapper: TestWrapper }); expect(mockScorecardHomepageCard).toHaveBeenCalledWith({ - aggregationId: 'github.open_prs', - metricId: 'github.open_prs', + aggregationId: 'github.openPrs', + metricId: 'github.openPrs', showSubheader: false, showInfo: false, }); @@ -190,32 +190,32 @@ describe('ScorecardPage', () => { it('should pass KPI aggregation id and backing metric id separately', () => { mockUseParams.mockReturnValue({ aggregationId: 'openPrsKpi', - metricId: 'github.open_prs', + metricId: 'github.openPrs', }); render(, { wrapper: TestWrapper }); expect(mockScorecardHomepageCard).toHaveBeenCalledWith({ aggregationId: 'openPrsKpi', - metricId: 'github.open_prs', + metricId: 'github.openPrs', showSubheader: false, showInfo: false, }); expect(mockEntitiesTable).toHaveBeenCalledWith( - expect.objectContaining({ metricId: 'github.open_prs' }), + expect.objectContaining({ metricId: 'github.openPrs' }), ); }); it('should update header title when setMetricTitle is called from EntitiesTable', () => { mockUseParams.mockReturnValue({ - aggregationId: 'github.open_prs', - metricId: 'github.open_prs', + aggregationId: 'github.openPrs', + metricId: 'github.openPrs', }); render(, { wrapper: TestWrapper }); expect(mockScorecardPageHeader).toHaveBeenLastCalledWith( - expect.objectContaining({ title: 'github.open_prs' }), + expect.objectContaining({ title: 'github.openPrs' }), ); act(() => { diff --git a/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetric.test.tsx b/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetric.test.tsx index b3b1ecfb89..5ac45f6d45 100644 --- a/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetric.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetric.test.tsx @@ -41,7 +41,7 @@ describe('useMetric', () => { }; const mockMetric: Metric = { - id: 'github.open_prs', + id: 'github.openPrs', title: 'GitHub open PRs', description: 'Current count of open Pull Requests for a given GitHub repository.', @@ -64,7 +64,7 @@ describe('useMetric', () => { } as any); const { result } = renderHook(() => - useMetric({ metricId: 'github.open_prs' }), + useMetric({ metricId: 'github.openPrs' }), ); expect(result.current).toEqual({ @@ -82,7 +82,7 @@ describe('useMetric', () => { } as any); const { result } = renderHook(() => - useMetric({ metricId: 'github.open_prs' }), + useMetric({ metricId: 'github.openPrs' }), ); expect(result.current).toEqual({ @@ -101,7 +101,7 @@ describe('useMetric', () => { } as any); const { result } = renderHook(() => - useMetric({ metricId: 'github.open_prs' }), + useMetric({ metricId: 'github.openPrs' }), ); expect(result.current).toEqual({ diff --git a/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetricDisplayLabels.test.tsx b/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetricDisplayLabels.test.tsx index 2f72ab5869..f9730ad7ab 100644 --- a/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetricDisplayLabels.test.tsx +++ b/workspaces/scorecard/plugins/scorecard/src/hooks/__tests__/useMetricDisplayLabels.test.tsx @@ -28,7 +28,7 @@ describe('useMetricDisplayLabels', () => { const mockT = jest.fn(); const metric = { - id: 'github.open_prs', + id: 'github.openPrs', title: 'GitHub open PRs', description: 'Current count of open Pull Requests for a given GitHub repository.', @@ -55,8 +55,8 @@ describe('useMetricDisplayLabels', () => { it('should return translated title and description when translation exists', () => { mockT.mockImplementation((key: string) => { - if (key === 'metric.github.open_prs.title') return 'Translated Title'; - if (key === 'metric.github.open_prs.description') + if (key === 'metric.github.openPrs.title') return 'Translated Title'; + if (key === 'metric.github.openPrs.description') return 'Translated Description'; return key; }); @@ -83,7 +83,7 @@ describe('useMetricDisplayLabels', () => { it('should use translated title but original description when only title translation exists', () => { mockT.mockImplementation((key: string) => { - if (key === 'metric.github.open_prs.title') return 'Translated Title'; + if (key === 'metric.github.openPrs.title') return 'Translated Title'; return key; }); diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/de.ts b/workspaces/scorecard/plugins/scorecard/src/translations/de.ts index db35af36e4..0a3c6b6bd2 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/de.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/de.ts @@ -87,60 +87,59 @@ const scorecardTranslationDe = createTranslationMessages({ 'metric.filecheck.description': 'Prüft, ob die Datei {{name}} im Repository existiert.', 'metric.filecheck.title': 'Dateiprüfung: {{name}}', - 'metric.github.open_prs.description': + 'metric.github.openPrs.description': 'Aktuelle Anzahl offener Pull Requests für ein bestimmtes GitHub-Repository.', - 'metric.github.open_prs.title': 'GitHub offene PRs', + 'metric.github.openPrs.title': 'GitHub offene PRs', 'metric.homepageEntityCalculationHealth': '{{healthy}} / {{total}} Entitäten ohne Metrikberechnungsfehler', 'metric.homepageEntityHealthRatio': '{{healthy}}/{{total}} Entitäten', - 'metric.jira.open_issues.description': + 'metric.jira.openIssues.description': 'Zeigt die Anzahl der kritischen, blockierenden Vorgänge an, die aktuell in Jira offen sind.', - 'metric.jira.open_issues.title': 'Jira-Tickets öffnen und blockieren', + 'metric.jira.openIssues.title': 'Jira-Tickets öffnen und blockieren', 'metric.lastUpdated': 'Letzte Aktualisierung: {{timestamp}}', 'metric.lastUpdatedNotAvailable': 'Letzte Aktualisierung: Nicht verfügbar', 'metric.someEntitiesNotReportingValues': 'Einige Organisationen melden keine Werte, die sich auf diese Kennzahl beziehen.', - 'metric.sonarqube.code_coverage.description': + 'metric.sonarqube.codeCoverage.description': 'Gesamtcodeabdeckung in SonarQube in Prozent.', - 'metric.sonarqube.code_coverage.title': 'SonarQube-Codeabdeckung', - 'metric.sonarqube.code_duplications.description': + 'metric.sonarqube.codeCoverage.title': 'SonarQube-Codeabdeckung', + 'metric.sonarqube.codeDuplications.description': 'Prozentsatz doppelter Zeilen in SonarQube.', - 'metric.sonarqube.code_duplications.title': 'SonarQube-Code-Duplizierungen', - 'metric.sonarqube.maintainability_issues.description': + 'metric.sonarqube.codeDuplications.title': 'SonarQube-Code-Duplizierungen', + 'metric.sonarqube.maintainabilityIssues.description': 'Anzahl offener Code-Smells in SonarQube.', - 'metric.sonarqube.maintainability_issues.title': + 'metric.sonarqube.maintainabilityIssues.title': 'SonarQube-Wartbarkeitsprobleme', - 'metric.sonarqube.maintainability_rating.description': + 'metric.sonarqube.maintainabilityRating.description': 'SonarQube-Wartungsbewertung.', - 'metric.sonarqube.maintainability_rating.title': + 'metric.sonarqube.maintainabilityRating.title': 'SonarQube-Wartbarkeitsbewertung', - 'metric.sonarqube.open_issues.description': + 'metric.sonarqube.openIssues.description': 'Anzahl der offenen Tickets (OFFEN, BESTÄTIGT, WIEDERERÖFFNET) in SonarQube.', - 'metric.sonarqube.open_issues.title': 'Offene Probleme bei SonarQube', - 'metric.sonarqube.quality_gate.description': + 'metric.sonarqube.openIssues.title': 'Offene Probleme bei SonarQube', + 'metric.sonarqube.qualityGate.description': 'Ob das Projekt die SonarQube-Qualitätsprüfung besteht.', - 'metric.sonarqube.quality_gate.title': 'SonarQube Qualitätsgate-Status', - 'metric.sonarqube.reliability_issues.description': + 'metric.sonarqube.qualityGate.title': 'SonarQube Qualitätsgate-Status', + 'metric.sonarqube.reliabilityIssues.description': 'Anzahl offener Fehler in SonarQube.', - 'metric.sonarqube.reliability_issues.title': + 'metric.sonarqube.reliabilityIssues.title': 'Zuverlässigkeitsprobleme von SonarQube', - 'metric.sonarqube.reliability_rating.description': + 'metric.sonarqube.reliabilityRating.description': 'SonarQube-Zuverlässigkeitsbewertung.', - 'metric.sonarqube.reliability_rating.title': + 'metric.sonarqube.reliabilityRating.title': 'SonarQube-Zuverlässigkeitsbewertung', - 'metric.sonarqube.security_hotspots.description': + 'metric.sonarqube.securityHotspots.description': 'Anzahl der in SonarQube zu überprüfenden Sicherheits-Hotspots.', - 'metric.sonarqube.security_hotspots.title': - 'SonarQube Sicherheits-Hotspots', - 'metric.sonarqube.security_issues.description': + 'metric.sonarqube.securityHotspots.title': 'SonarQube Sicherheits-Hotspots', + 'metric.sonarqube.securityIssues.description': 'Anzahl offener Sicherheitslücken in SonarQube.', - 'metric.sonarqube.security_issues.title': 'SonarQube-Sicherheitsprobleme', - 'metric.sonarqube.security_rating.description': + 'metric.sonarqube.securityIssues.title': 'SonarQube-Sicherheitsprobleme', + 'metric.sonarqube.securityRating.description': 'SonarQube-Sicherheitsbewertung.', - 'metric.sonarqube.security_rating.title': 'SonarQube-Sicherheitsbewertung', - 'metric.sonarqube.security_review_rating.description': + 'metric.sonarqube.securityRating.title': 'SonarQube-Sicherheitsbewertung', + 'metric.sonarqube.securityReviewRating.description': 'SonarQube-Sicherheitsbewertung.', - 'metric.sonarqube.security_review_rating.title': + 'metric.sonarqube.securityReviewRating.title': 'SonarQube Sicherheitsbewertung', 'notFound.altText': 'Seite nicht gefunden', 'notFound.contactSupport': 'Kontaktieren Sie den Support.', diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/es.ts b/workspaces/scorecard/plugins/scorecard/src/translations/es.ts index a809361ae5..decba931cb 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/es.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/es.ts @@ -88,64 +88,64 @@ const scorecardTranslationEs = createTranslationMessages({ 'metric.filecheck.description': 'Comprueba si el archivo {{name}} existe en el repositorio.', 'metric.filecheck.title': 'Verificación de archivo: {{name}}', - 'metric.github.open_prs.description': + 'metric.github.openPrs.description': 'Recuento actual de solicitudes de extracción abiertas para un repositorio de GitHub determinado.', - 'metric.github.open_prs.title': 'PR abiertas de GitHub', + 'metric.github.openPrs.title': 'PR abiertas de GitHub', 'metric.homepageEntityCalculationHealth': '{{healthy}} / {{total}} entidades sin errores de cálculo de métricas', 'metric.homepageEntityHealthRatio': '{{healthy}}/{{total}} entidades', - 'metric.jira.open_issues.description': + 'metric.jira.openIssues.description': 'Destaca la cantidad de problemas críticos y bloqueantes que están abiertos actualmente en Jira.', - 'metric.jira.open_issues.title': 'Tickets de bloqueo abiertos en Jira', + 'metric.jira.openIssues.title': 'Tickets de bloqueo abiertos en Jira', 'metric.lastUpdated': 'Última actualización: {{timestamp}}', 'metric.lastUpdatedNotAvailable': 'Última actualización: no disponible', 'metric.someEntitiesNotReportingValues': 'Algunas entidades no informan valores relacionados con esta métrica.', - 'metric.sonarqube.code_coverage.description': + 'metric.sonarqube.codeCoverage.description': 'Porcentaje general de cobertura de código en SonarQube.', - 'metric.sonarqube.code_coverage.title': 'Cobertura de código de SonarQube', - 'metric.sonarqube.code_duplications.description': + 'metric.sonarqube.codeCoverage.title': 'Cobertura de código de SonarQube', + 'metric.sonarqube.codeDuplications.description': 'Porcentaje de líneas duplicadas en SonarQube.', - 'metric.sonarqube.code_duplications.title': + 'metric.sonarqube.codeDuplications.title': 'Duplicaciones de código de SonarQube', - 'metric.sonarqube.maintainability_issues.description': + 'metric.sonarqube.maintainabilityIssues.description': 'Cantidad de code smells abiertos en SonarQube.', - 'metric.sonarqube.maintainability_issues.title': + 'metric.sonarqube.maintainabilityIssues.title': 'Problemas de mantenibilidad de SonarQube', - 'metric.sonarqube.maintainability_rating.description': + 'metric.sonarqube.maintainabilityRating.description': 'Calificación de mantenibilidad de SonarQube.', - 'metric.sonarqube.maintainability_rating.title': + 'metric.sonarqube.maintainabilityRating.title': 'Calificación de mantenibilidad de SonarQube', - 'metric.sonarqube.open_issues.description': + 'metric.sonarqube.openIssues.description': 'Cantidad de problemas abiertos (ABIERTOS, CONFIRMADOS, REABIERTOS) en SonarQube.', - 'metric.sonarqube.open_issues.title': 'Problemas abiertos de SonarQube', - 'metric.sonarqube.quality_gate.description': + 'metric.sonarqube.openIssues.title': 'Problemas abiertos de SonarQube', + 'metric.sonarqube.qualityGate.description': 'Si el proyecto supera el control de calidad de SonarQube.', - 'metric.sonarqube.quality_gate.title': + 'metric.sonarqube.qualityGate.title': 'Estado del control de calidad de SonarQube', - 'metric.sonarqube.reliability_issues.description': + 'metric.sonarqube.reliabilityIssues.description': 'Cantidad de errores abiertos en SonarQube.', - 'metric.sonarqube.reliability_issues.title': + 'metric.sonarqube.reliabilityIssues.title': 'Problemas de confiabilidad de SonarQube', - 'metric.sonarqube.reliability_rating.description': + 'metric.sonarqube.reliabilityRating.description': 'Calificación de confiabilidad de SonarQube.', - 'metric.sonarqube.reliability_rating.title': + 'metric.sonarqube.reliabilityRating.title': 'Calificación de confiabilidad de SonarQube', - 'metric.sonarqube.security_hotspots.description': + 'metric.sonarqube.securityHotspots.description': 'Cantidad de puntos críticos de seguridad que deben revisarse en SonarQube.', - 'metric.sonarqube.security_hotspots.title': + 'metric.sonarqube.securityHotspots.title': 'Puntos críticos de seguridad SonarQube', - 'metric.sonarqube.security_issues.description': + 'metric.sonarqube.securityIssues.description': 'Cantidad de vulnerabilidades de seguridad abiertas en SonarQube.', - 'metric.sonarqube.security_issues.title': + 'metric.sonarqube.securityIssues.title': 'Problemas de seguridad de SonarQube', - 'metric.sonarqube.security_rating.description': + 'metric.sonarqube.securityRating.description': 'Calificación de seguridad de SonarQube.', - 'metric.sonarqube.security_rating.title': + 'metric.sonarqube.securityRating.title': 'Calificación de seguridad de SonarQube', - 'metric.sonarqube.security_review_rating.description': + 'metric.sonarqube.securityReviewRating.description': 'Calificación de la revisión de seguridad de SonarQube.', - 'metric.sonarqube.security_review_rating.title': + 'metric.sonarqube.securityReviewRating.title': 'Calificación de la revisión de seguridad de SonarQube', 'notFound.altText': 'Pagina no encontrada', 'notFound.contactSupport': 'Comuníquese con Soporte', diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/fr.ts b/workspaces/scorecard/plugins/scorecard/src/translations/fr.ts index 7e94ac5e8a..4528ec9e20 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/fr.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/fr.ts @@ -89,63 +89,62 @@ const scorecardTranslationFr = createTranslationMessages({ 'metric.filecheck.description': 'Vérifie si le fichier {{name}} existe dans le référentiel.', 'metric.filecheck.title': 'Vérification du fichier : {{name}}', - 'metric.github.open_prs.description': + 'metric.github.openPrs.description': "Nombre actuel de demandes d'extraction ouvertes pour un référentiel GitHub donné.", - 'metric.github.open_prs.title': 'GitHub pull requests ouvertes', + 'metric.github.openPrs.title': 'GitHub pull requests ouvertes', 'metric.homepageEntityCalculationHealth': '{{healthy}} / {{total}} entités sans erreurs de calcul de métrique', 'metric.homepageEntityHealthRatio': '{{healthy}}/{{total}} entités', - 'metric.jira.open_issues.description': + 'metric.jira.openIssues.description': 'Ce document met en évidence le nombre de problèmes critiques et bloquants actuellement ouverts dans Jira.', - 'metric.jira.open_issues.title': 'Tickets de blocage ouverts Jira', + 'metric.jira.openIssues.title': 'Tickets de blocage ouverts Jira', 'metric.lastUpdated': 'Dernière mise à jour : {{timestamp}}', 'metric.lastUpdatedNotAvailable': 'Dernière mise à jour : Non disponible', 'metric.someEntitiesNotReportingValues': 'Certaines entités ne communiquent pas les valeurs relatives à cet indicateur.', - 'metric.sonarqube.code_coverage.description': + 'metric.sonarqube.codeCoverage.description': 'Pourcentage global de couverture de code dans SonarQube.', - 'metric.sonarqube.code_coverage.title': 'Couverture de code SonarQube', - 'metric.sonarqube.code_duplications.description': + 'metric.sonarqube.codeCoverage.title': 'Couverture de code SonarQube', + 'metric.sonarqube.codeDuplications.description': 'Pourcentage de lignes dupliquées dans SonarQube.', - 'metric.sonarqube.code_duplications.title': - 'Duplications de code SonarQube', - 'metric.sonarqube.maintainability_issues.description': + 'metric.sonarqube.codeDuplications.title': 'Duplications de code SonarQube', + 'metric.sonarqube.maintainabilityIssues.description': "Nombre d'anomalies de code ouvert dans SonarQube.", - 'metric.sonarqube.maintainability_issues.title': + 'metric.sonarqube.maintainabilityIssues.title': 'Problèmes de maintenabilité de SonarQube', - 'metric.sonarqube.maintainability_rating.description': + 'metric.sonarqube.maintainabilityRating.description': 'Évaluation de la maintenabilité de SonarQube.', - 'metric.sonarqube.maintainability_rating.title': + 'metric.sonarqube.maintainabilityRating.title': 'Évaluation de la maintenabilité de SonarQube', - 'metric.sonarqube.open_issues.description': + 'metric.sonarqube.openIssues.description': 'Nombre de problèmes ouverts (OUVERTS, CONFIRMÉS, RÉOUVERTS) dans SonarQube.', - 'metric.sonarqube.open_issues.title': 'Problèmes ouverts de SonarQube', - 'metric.sonarqube.quality_gate.description': + 'metric.sonarqube.openIssues.title': 'Problèmes ouverts de SonarQube', + 'metric.sonarqube.qualityGate.description': 'Si le projet réussit le contrôle qualité SonarQube.', - 'metric.sonarqube.quality_gate.title': 'État du seuil de qualité SonarQube', - 'metric.sonarqube.reliability_issues.description': + 'metric.sonarqube.qualityGate.title': 'État du seuil de qualité SonarQube', + 'metric.sonarqube.reliabilityIssues.description': 'Nombre de bogues ouverts dans SonarQube.', - 'metric.sonarqube.reliability_issues.title': + 'metric.sonarqube.reliabilityIssues.title': 'Problèmes de fiabilité de SonarQube', - 'metric.sonarqube.reliability_rating.description': + 'metric.sonarqube.reliabilityRating.description': 'Évaluation de la fiabilité de SonarQube.', - 'metric.sonarqube.reliability_rating.title': + 'metric.sonarqube.reliabilityRating.title': 'Évaluation de la fiabilité de SonarQube', - 'metric.sonarqube.security_hotspots.description': + 'metric.sonarqube.securityHotspots.description': 'Nombre de points chauds de sécurité à examiner dans SonarQube.', - 'metric.sonarqube.security_hotspots.title': + 'metric.sonarqube.securityHotspots.title': "Points d'accès de sécurité SonarQube", - 'metric.sonarqube.security_issues.description': + 'metric.sonarqube.securityIssues.description': 'Nombre de failles de sécurité ouvertes dans SonarQube.', - 'metric.sonarqube.security_issues.title': + 'metric.sonarqube.securityIssues.title': 'Problèmes de sécurité de SonarQube', - 'metric.sonarqube.security_rating.description': + 'metric.sonarqube.securityRating.description': 'Évaluation de sécurité de SonarQube.', - 'metric.sonarqube.security_rating.title': + 'metric.sonarqube.securityRating.title': 'Évaluation de sécurité de SonarQube', - 'metric.sonarqube.security_review_rating.description': + 'metric.sonarqube.securityReviewRating.description': 'Évaluation de la sécurité de SonarQube.', - 'metric.sonarqube.security_review_rating.title': + 'metric.sonarqube.securityReviewRating.title': 'Évaluation de la sécurité de SonarQube', 'notFound.altText': 'Page introuvable', 'notFound.contactSupport': "Contactez l'assistance", diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/it.ts b/workspaces/scorecard/plugins/scorecard/src/translations/it.ts index 242ab68d98..1c26f97982 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/it.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/it.ts @@ -89,64 +89,63 @@ const scorecardTranslationIt = createTranslationMessages({ 'metric.filecheck.description': 'Verifica se il file {{name}} esiste nel repository.', 'metric.filecheck.title': 'Verifica del file: {{name}}', - 'metric.github.open_prs.description': + 'metric.github.openPrs.description': 'Numero attuale di richiesta pull aperte per un determinato repository di GitHub.', - 'metric.github.open_prs.title': 'RP aperte su GitHub', + 'metric.github.openPrs.title': 'RP aperte su GitHub', 'metric.homepageEntityCalculationHealth': '{{healthy}} / {{total}} entità senza errori di calcolo della metrica', 'metric.homepageEntityHealthRatio': '{{healthy}}/{{total}} entità', - 'metric.jira.open_issues.description': + 'metric.jira.openIssues.description': 'Evidenzia il numero di problemi critici e bloccanti attualmente aperti in Jira.', - 'metric.jira.open_issues.title': 'Ticket di blocco aperti in Jira', + 'metric.jira.openIssues.title': 'Ticket di blocco aperti in Jira', 'metric.lastUpdated': 'Ultimo aggiornamento: {{timestamp}}', 'metric.lastUpdatedNotAvailable': 'Ultimo aggiornamento: non disponibile', 'metric.someEntitiesNotReportingValues': 'Alcune entità non comunicano i valori relativi a questa metrica.', - 'metric.sonarqube.code_coverage.description': + 'metric.sonarqube.codeCoverage.description': 'Percentuale complessiva di copertura codice in SonarQube.', - 'metric.sonarqube.code_coverage.title': 'Copertura codice in SonarQube', - 'metric.sonarqube.code_duplications.description': + 'metric.sonarqube.codeCoverage.title': 'Copertura codice in SonarQube', + 'metric.sonarqube.codeDuplications.description': 'Percentuale di linee duplicate in SonarQube.', - 'metric.sonarqube.code_duplications.title': + 'metric.sonarqube.codeDuplications.title': 'Duplicazioni del codice in SonarQube', - 'metric.sonarqube.maintainability_issues.description': + 'metric.sonarqube.maintainabilityIssues.description': 'Numero di code smell non risolti in SonarQube.', - 'metric.sonarqube.maintainability_issues.title': + 'metric.sonarqube.maintainabilityIssues.title': 'Problemi di manutenibilità di SonarQube', - 'metric.sonarqube.maintainability_rating.description': + 'metric.sonarqube.maintainabilityRating.description': 'Valutazione di manutenibilità di SonarQube.', - 'metric.sonarqube.maintainability_rating.title': + 'metric.sonarqube.maintainabilityRating.title': 'Valutazione di manutenibilità di SonarQube', - 'metric.sonarqube.open_issues.description': + 'metric.sonarqube.openIssues.description': 'Numero dei problemi aperti (APERTI, CONFERMATI, RIAPERTI) in SonarQube.', - 'metric.sonarqube.open_issues.title': 'Problemi aperti in SonarQube', - 'metric.sonarqube.quality_gate.description': + 'metric.sonarqube.openIssues.title': 'Problemi aperti in SonarQube', + 'metric.sonarqube.qualityGate.description': 'Se il progetto supera il quality gate di SonarQube.', - 'metric.sonarqube.quality_gate.title': - 'Stato del Quality Gate di SonarQube', - 'metric.sonarqube.reliability_issues.description': + 'metric.sonarqube.qualityGate.title': 'Stato del Quality Gate di SonarQube', + 'metric.sonarqube.reliabilityIssues.description': 'Numero di bug aperti in SonarQube.', - 'metric.sonarqube.reliability_issues.title': + 'metric.sonarqube.reliabilityIssues.title': 'Problemi di affidabilità di SonarQube', - 'metric.sonarqube.reliability_rating.description': + 'metric.sonarqube.reliabilityRating.description': 'Valutazione di affidabilità di SonarQube.', - 'metric.sonarqube.reliability_rating.title': + 'metric.sonarqube.reliabilityRating.title': 'Valutazione di affidabilità di SonarQube', - 'metric.sonarqube.security_hotspots.description': + 'metric.sonarqube.securityHotspots.description': 'Numero di hotspot di sicurezza da rivedere in SonarQube.', - 'metric.sonarqube.security_hotspots.title': + 'metric.sonarqube.securityHotspots.title': 'Hotspot di sicurezza di SonarQube', - 'metric.sonarqube.security_issues.description': + 'metric.sonarqube.securityIssues.description': 'Numero di vulnerabilità di sicurezza aperte in SonarQube.', - 'metric.sonarqube.security_issues.title': + 'metric.sonarqube.securityIssues.title': 'Problemi di sicurezza di SonarQube', - 'metric.sonarqube.security_rating.description': + 'metric.sonarqube.securityRating.description': 'Valutazione di sicurezza di SonarQube.', - 'metric.sonarqube.security_rating.title': + 'metric.sonarqube.securityRating.title': 'Valutazione di sicurezza di SonarQube', - 'metric.sonarqube.security_review_rating.description': + 'metric.sonarqube.securityReviewRating.description': 'Valutazione di sicurezza di SonarQube.', - 'metric.sonarqube.security_review_rating.title': + 'metric.sonarqube.securityReviewRating.title': 'Valutazione di sicurezza di SonarQube', 'notFound.altText': 'Pagina non trovata', 'notFound.contactSupport': 'Contatta il supporto', diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/ja.ts b/workspaces/scorecard/plugins/scorecard/src/translations/ja.ts index aaf9571662..9f091d4843 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/ja.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/ja.ts @@ -88,60 +88,60 @@ const scorecardTranslationJa = createTranslationMessages({ 'metric.filecheck.description': 'リポジトリー内に {{name}} ファイルが存在するかどうかを確認します。', 'metric.filecheck.title': 'ファイルチェック: {{name}}', - 'metric.github.open_prs.description': + 'metric.github.openPrs.description': '特定の GitHub リポジトリーにおけるオープン状態のプルリクエストの数。', - 'metric.github.open_prs.title': 'GitHub のオープン状態の PR', + 'metric.github.openPrs.title': 'GitHub のオープン状態の PR', 'metric.homepageEntityCalculationHealth': 'メトリクス計算エラーのないエンティティー: {{healthy}} / {{total}}', 'metric.homepageEntityHealthRatio': '{{healthy}}/{{total}} エンティティー', - 'metric.jira.open_issues.description': + 'metric.jira.openIssues.description': 'Jira で現在オープン状態になっている、重大かつ進行を妨げている課題の数を明示します。', - 'metric.jira.open_issues.title': + 'metric.jira.openIssues.title': 'Jira のオープン状態の進行を妨げているチケット', 'metric.lastUpdated': '最終更新: {{timestamp}}', 'metric.lastUpdatedNotAvailable': '最終更新: 利用不可', 'metric.someEntitiesNotReportingValues': 'このメトリクスに関連する値を報告していないエンティティーがあります。', - 'metric.sonarqube.code_coverage.description': + 'metric.sonarqube.codeCoverage.description': 'SonarQube におけるコードカバレッジ全体の割合。', - 'metric.sonarqube.code_coverage.title': 'SonarQube のコードカバレッジ', - 'metric.sonarqube.code_duplications.description': + 'metric.sonarqube.codeCoverage.title': 'SonarQube のコードカバレッジ', + 'metric.sonarqube.codeDuplications.description': 'SonarQube の重複行の割合。', - 'metric.sonarqube.code_duplications.title': 'SonarQube のコード重複', - 'metric.sonarqube.maintainability_issues.description': + 'metric.sonarqube.codeDuplications.title': 'SonarQube のコード重複', + 'metric.sonarqube.maintainabilityIssues.description': 'SonarQube におけるオープン状態のコードスメルの数。', - 'metric.sonarqube.maintainability_issues.title': + 'metric.sonarqube.maintainabilityIssues.title': 'SonarQube の保守性に関する問題', - 'metric.sonarqube.maintainability_rating.description': + 'metric.sonarqube.maintainabilityRating.description': 'SonarQube の保守性評価。', - 'metric.sonarqube.maintainability_rating.title': 'SonarQube の保守性評価', - 'metric.sonarqube.open_issues.description': + 'metric.sonarqube.maintainabilityRating.title': 'SonarQube の保守性評価', + 'metric.sonarqube.openIssues.description': 'SonarQube におけるオープン状態のイシュー (OPEN、CONFIRMED、REOPENED) の数。', - 'metric.sonarqube.open_issues.title': 'SonarQube のオープン状態のイシュー', - 'metric.sonarqube.quality_gate.description': + 'metric.sonarqube.openIssues.title': 'SonarQube のオープン状態のイシュー', + 'metric.sonarqube.qualityGate.description': 'プロジェクトが SonarQube の品質基準を合格しているかどうか。', - 'metric.sonarqube.quality_gate.title': 'SonarQube の品質基準ステータス', - 'metric.sonarqube.reliability_issues.description': + 'metric.sonarqube.qualityGate.title': 'SonarQube の品質基準ステータス', + 'metric.sonarqube.reliabilityIssues.description': 'SonarQube におけるオープン状態のバグの数。', - 'metric.sonarqube.reliability_issues.title': + 'metric.sonarqube.reliabilityIssues.title': 'SonarQube の信頼性に関する問題', - 'metric.sonarqube.reliability_rating.description': + 'metric.sonarqube.reliabilityRating.description': 'SonarQube の信頼性評価。', - 'metric.sonarqube.reliability_rating.title': 'SonarQube の信頼性評価', - 'metric.sonarqube.security_hotspots.description': + 'metric.sonarqube.reliabilityRating.title': 'SonarQube の信頼性評価', + 'metric.sonarqube.securityHotspots.description': 'SonarQube で確認すべきセキュリティーホットスポットの数。', - 'metric.sonarqube.security_hotspots.title': + 'metric.sonarqube.securityHotspots.title': 'SonarQube のセキュリティーホットスポット', - 'metric.sonarqube.security_issues.description': + 'metric.sonarqube.securityIssues.description': 'SonarQube におけるオープン状態のセキュリティー脆弱性の数。', - 'metric.sonarqube.security_issues.title': + 'metric.sonarqube.securityIssues.title': 'SonarQube のセキュリティーに関する問題', - 'metric.sonarqube.security_rating.description': + 'metric.sonarqube.securityRating.description': 'SonarQube のセキュリティー評価。', - 'metric.sonarqube.security_rating.title': 'SonarQube セキュリティー評価', - 'metric.sonarqube.security_review_rating.description': + 'metric.sonarqube.securityRating.title': 'SonarQube セキュリティー評価', + 'metric.sonarqube.securityReviewRating.description': 'SonarQube のセキュリティーレビュー評価。', - 'metric.sonarqube.security_review_rating.title': + 'metric.sonarqube.securityReviewRating.title': 'SonarQube のセキュリティーレビュー評価', 'notFound.altText': 'ページが見つかりません', 'notFound.contactSupport': 'サポートにお問い合わせください', diff --git a/workspaces/scorecard/plugins/scorecard/src/translations/ref.ts b/workspaces/scorecard/plugins/scorecard/src/translations/ref.ts index d76080342c..1bfeed25a0 100644 --- a/workspaces/scorecard/plugins/scorecard/src/translations/ref.ts +++ b/workspaces/scorecard/plugins/scorecard/src/translations/ref.ts @@ -81,62 +81,62 @@ export const scorecardMessages = { // Metric translations metric: { - 'github.open_prs': { + 'github.openPrs': { title: 'GitHub open PRs', description: 'Current count of open Pull Requests for a given GitHub repository.', }, - 'jira.open_issues': { + 'jira.openIssues': { title: 'Jira open blocking tickets', description: 'Highlights the number of critical, blocking issues that are currently open in Jira.', }, - 'sonarqube.quality_gate': { + 'sonarqube.qualityGate': { title: 'SonarQube Quality Gate Status', description: 'Whether the project passes its SonarQube quality gate.', }, - 'sonarqube.open_issues': { + 'sonarqube.openIssues': { title: 'SonarQube Open Issues', description: 'Count of open issues (OPEN, CONFIRMED, REOPENED) in SonarQube.', }, - 'sonarqube.security_rating': { + 'sonarqube.securityRating': { title: 'SonarQube Security Rating', description: 'SonarQube security rating.', }, - 'sonarqube.security_issues': { + 'sonarqube.securityIssues': { title: 'SonarQube Security Issues', description: 'Count of open security vulnerabilities in SonarQube.', }, - 'sonarqube.security_review_rating': { + 'sonarqube.securityReviewRating': { title: 'SonarQube Security Review Rating', description: 'SonarQube security review rating.', }, - 'sonarqube.security_hotspots': { + 'sonarqube.securityHotspots': { title: 'SonarQube Security Hotspots', description: 'Count of security hotspots to review in SonarQube.', }, - 'sonarqube.reliability_rating': { + 'sonarqube.reliabilityRating': { title: 'SonarQube Reliability Rating', description: 'SonarQube reliability rating.', }, - 'sonarqube.reliability_issues': { + 'sonarqube.reliabilityIssues': { title: 'SonarQube Reliability Issues', description: 'Count of open bugs in SonarQube.', }, - 'sonarqube.maintainability_rating': { + 'sonarqube.maintainabilityRating': { title: 'SonarQube Maintainability Rating', description: 'SonarQube maintainability rating.', }, - 'sonarqube.maintainability_issues': { + 'sonarqube.maintainabilityIssues': { title: 'SonarQube Maintainability Issues', description: 'Count of open code smells in SonarQube.', }, - 'sonarqube.code_coverage': { + 'sonarqube.codeCoverage': { title: 'SonarQube Code Coverage', description: 'Overall code coverage percentage in SonarQube.', }, - 'sonarqube.code_duplications': { + 'sonarqube.codeDuplications': { title: 'SonarQube Code Duplications', description: 'Percentage of duplicated lines in SonarQube.', }, diff --git a/workspaces/scorecard/plugins/scorecard/src/utils/__tests__/translationUtils.test.ts b/workspaces/scorecard/plugins/scorecard/src/utils/__tests__/translationUtils.test.ts index 17f4d5a8a4..c94757922e 100644 --- a/workspaces/scorecard/plugins/scorecard/src/utils/__tests__/translationUtils.test.ts +++ b/workspaces/scorecard/plugins/scorecard/src/utils/__tests__/translationUtils.test.ts @@ -34,10 +34,10 @@ const createMockT = (translations: Record): MockT => { describe('resolveMetricTranslation', () => { it('returns exact translation when key exists', () => { const t = createMockT({ - 'metric.github.open_prs.title': 'GitHub open PRs', + 'metric.github.openPrs.title': 'GitHub open PRs', }); - expect(resolveMetricTranslation(t as any, 'github.open_prs', 'title')).toBe( + expect(resolveMetricTranslation(t as any, 'github.openPrs', 'title')).toBe( 'GitHub open PRs', ); }); @@ -146,13 +146,13 @@ describe('resolveMetricTranslation', () => { it('prefers translation over fallback when translation exists', () => { const t = createMockT({ - 'metric.github.open_prs.title': 'GitHub open PRs', + 'metric.github.openPrs.title': 'GitHub open PRs', }); expect( resolveMetricTranslation( t as any, - 'github.open_prs', + 'github.openPrs', 'title', 'Fallback Title', ), diff --git a/workspaces/scorecard/plugins/scorecard/src/utils/translationUtils.ts b/workspaces/scorecard/plugins/scorecard/src/utils/translationUtils.ts index fade4f125f..79f82a908b 100644 --- a/workspaces/scorecard/plugins/scorecard/src/utils/translationUtils.ts +++ b/workspaces/scorecard/plugins/scorecard/src/utils/translationUtils.ts @@ -24,7 +24,7 @@ type ScorecardTranslationFunction = TranslationFunction< /** * Resolves a metric's translated title or description using a cascading lookup: * - * 1. Exact key: metric.. (e.g. metric.github.open_prs.title) + * 1. Exact key: metric.. (e.g. metric.github.openPrs.title) * 2. Template key: metric.. with name = * The first dot-separated segment is always the provider/namespace. * E.g. filecheck.codeowners -> metric.filecheck.title with name = codeowners