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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions report-app/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"builder": "@angular/build:karma",
"options": {
"tsConfig": "tsconfig.spec.json",
"browsers": "ChromeHeadless",
"assets": [
{
"glob": "**/*",
Expand Down
4 changes: 3 additions & 1 deletion report-app/src/app/app.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {TestBed} from '@angular/core/testing';
import {App} from './app';
import {provideRouter} from '@angular/router';

describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [App],
providers: [provideRouter([])],
}).compileComponents();
});

Expand All @@ -18,6 +20,6 @@ describe('App', () => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, report-app');
expect(compiled.querySelector('h1')?.textContent).toContain('Web Codegen Scorer');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {labelByRepairCount, createRepairAttemptGraphData} from './repair-attempt-graph-builder';
import {RunInfoFromReportServer} from '../../../../../runner/shared-interfaces';
import {BuildResultStatus} from '../../../../../runner/workers/builder/builder-types';

interface MockAssessmentResult {
finalAttempt: {
buildResult: {
status: BuildResultStatus;
};
};
repairAttempts: number;
}

interface MockRunInfo {
results: MockAssessmentResult[];
}

describe('repair-attempt-graph-builder', () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

First tests in the repo 🚀

describe('labelByRepairCount', () => {
it('should return "1 repair" for 1', () => {
expect(labelByRepairCount(1)).toBe('1 repair');
});

it('should return "2 repairs" for 2', () => {
expect(labelByRepairCount(2)).toBe('2 repairs');
});

it('should return "8 repairs" for 8', () => {
expect(labelByRepairCount(8)).toBe('8 repairs');
});

it('should return "9 repairs" for 9', () => {
expect(labelByRepairCount(9)).toBe('9 repairs');
});
});

describe('createRepairAttemptGraphData', () => {
it('should group repair attempt labels beyond 8', () => {
const mockReport: MockRunInfo = {
results: [
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 1},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 2},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 3},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 4},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 5},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 6},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 7},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 8},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 9},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 10},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 11},
],
};

const data = createRepairAttemptGraphData(mockReport as unknown as RunInfoFromReportServer);

expect(data.length).toBe(9);
expect(data[0].label).toBe('1 repair');
expect(data[1].label).toBe('2 repairs');
expect(data[7].label).toBe('8 repairs');
expect(data[8].label).toBe('9+ repairs');
});

it('should not group if distinct counts <= 8', () => {
const mockReport: MockRunInfo = {
results: [
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 1},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 3},
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 5},
],
};

const data = createRepairAttemptGraphData(mockReport as unknown as RunInfoFromReportServer);

expect(data.length).toBe(3);
expect(data[0].label).toBe('1 repair');
expect(data[1].label).toBe('3 repairs');
expect(data[2].label).toBe('5 repairs');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {BuildResultStatus} from '../../../../../runner/workers/builder/builder-t
import {ScoreCssVariable} from '../../shared/scoring';
import {StackedBarChartData} from '../../shared/visualization/stacked-bar-chart/stacked-bar-chart';

const MAX_VISIBLE_REPAIR_COUNT = 8;

/**
* Calculates the average number of repair attempts performed in a run.
*/
Expand Down Expand Up @@ -52,17 +54,41 @@ export function createRepairAttemptGraphData(report: RunInfoFromReportServer) {
.filter((k): k is number => typeof k === 'number')
.sort((a, b) => a - b);

// This graph might involve a bunch of sections. We want to scale them among all the possible color "grades".
if (intermediateRepairKeys.length <= MAX_VISIBLE_REPAIR_COUNT) {
for (const repairCount of intermediateRepairKeys) {
const applicationCount = repairsToAppCount.get(repairCount);
if (!applicationCount) continue;

for (let repairCount = 1; repairCount <= maxRepairCount; repairCount++) {
const applicationCount = repairsToAppCount.get(repairCount);
if (!applicationCount) continue;
data.push({
label: labelByRepairCount(repairCount),
color: colorByRepairCount(repairCount),
value: applicationCount,
});
}
} else {
const visibleKeys = intermediateRepairKeys.slice(0, MAX_VISIBLE_REPAIR_COUNT);
const hiddenKeys = intermediateRepairKeys.slice(MAX_VISIBLE_REPAIR_COUNT);
const maxVisible = visibleKeys[visibleKeys.length - 1];

data.push({
label: labelByRepairCount(repairCount),
color: colorByRepairCount(repairCount),
value: applicationCount,
});
for (const repairCount of visibleKeys) {
const applicationCount = repairsToAppCount.get(repairCount);
if (!applicationCount) continue;

data.push({
label: labelByRepairCount(repairCount),
color: colorByRepairCount(repairCount),
value: applicationCount,
});
}

const groupValue = hiddenKeys.reduce((acc, k) => acc + (repairsToAppCount.get(k) ?? 0), 0);
if (groupValue > 0) {
data.push({
label: `${maxVisible + 1}+ repairs`,
color: colorByRepairCount(maxVisible + 1),
value: groupValue,
});
}
}

// Handle 'Build failed even after all retries' - always maps to the "failure" grade.
Expand All @@ -77,17 +103,11 @@ export function createRepairAttemptGraphData(report: RunInfoFromReportServer) {
return data;
}

function labelByRepairCount(repairCount: number): string {
switch (repairCount) {
case 1:
return '1 repair';
case 2:
case 3:
case 4:
return `${repairCount} repairs`;
default:
return '5+ repairs';
export function labelByRepairCount(repairCount: number): string {
if (repairCount === 1) {
return '1 repair';
}
return `${repairCount} repairs`;
}

function colorByRepairCount(repairCount: number): string {
Expand Down
Loading