Skip to content

Commit 98adb71

Browse files
CopilotMattG57
andcommitted
Add repository count diagnostics for GitHub App installations
Co-authored-by: MattG57 <[email protected]>
1 parent 18bfaf8 commit 98adb71

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

backend/src/controllers/setup.controller.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface InstallationDiagnostic {
3232
octokitTest: OctokitTestResult | null;
3333
isValid: boolean;
3434
validationErrors: string[];
35+
repositoryCount: number;
3536
}
3637

3738
interface AppInfo {
@@ -55,6 +56,8 @@ interface DiagnosticsResponse {
5556
invalidInstallations: number;
5657
organizationNames: string[];
5758
accountTypes: Record<string, number>;
59+
repositoryCounts: Record<string, number>;
60+
totalRepositories: number;
5861
};
5962
}
6063

@@ -180,7 +183,9 @@ class SetupController {
180183
validInstallations: 0,
181184
invalidInstallations: 0,
182185
organizationNames: [],
183-
accountTypes: {}
186+
accountTypes: {},
187+
repositoryCounts: {},
188+
totalRepositories: 0
184189
}
185190
};
186191

@@ -213,7 +218,8 @@ class SetupController {
213218
hasOctokit: !!octokit,
214219
octokitTest: null,
215220
isValid: true,
216-
validationErrors: []
221+
validationErrors: [],
222+
repositoryCount: 0
217223
};
218224

219225
// Validate required fields
@@ -232,7 +238,7 @@ class SetupController {
232238
installationDiag.validationErrors.push('Missing account.type');
233239
}
234240

235-
// Test Octokit functionality
241+
// Test Octokit functionality and fetch repository count
236242
if (octokit) {
237243
try {
238244
// Test basic API call with the installation's octokit
@@ -243,17 +249,29 @@ class SetupController {
243249
appOwner: (authTest.data?.owner && 'login' in authTest.data.owner) ? authTest.data.owner.login : 'Unknown',
244250
permissions: authTest.data?.permissions || {}
245251
};
252+
253+
// Fetch repositories for this installation
254+
try {
255+
const repos = await octokit.request(installation.repositories_url);
256+
installationDiag.repositoryCount = repos.data.repositories?.length || 0;
257+
} catch (repoError) {
258+
// If repository fetching fails, log it but don't mark installation as invalid
259+
installationDiag.validationErrors.push(`Failed to fetch repositories: ${repoError instanceof Error ? repoError.message : 'Unknown error'}`);
260+
installationDiag.repositoryCount = 0;
261+
}
246262
} catch (error) {
247263
installationDiag.octokitTest = {
248264
success: false,
249265
error: error instanceof Error ? error.message : 'Unknown error'
250266
};
251267
installationDiag.isValid = false;
252268
installationDiag.validationErrors.push(`Octokit API test failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
269+
installationDiag.repositoryCount = 0;
253270
}
254271
} else {
255272
installationDiag.isValid = false;
256273
installationDiag.validationErrors.push('Octokit instance is missing');
274+
installationDiag.repositoryCount = 0;
257275
}
258276

259277
// Update summary
@@ -270,6 +288,11 @@ class SetupController {
270288
const accountType = installation.account?.type || 'Unknown';
271289
diagnostics.summary.accountTypes[accountType] = (diagnostics.summary.accountTypes[accountType] || 0) + 1;
272290

291+
// Track repository counts per organization
292+
const orgName = installation.account?.login || 'Unknown';
293+
diagnostics.summary.repositoryCounts[orgName] = installationDiag.repositoryCount;
294+
diagnostics.summary.totalRepositories += installationDiag.repositoryCount;
295+
273296
diagnostics.installations.push(installationDiag);
274297
}
275298

frontend/src/app/main/diagnostics/main-diagnostics.component.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { DiagnosticsResponse } from '../../types/diagnostics.types';
4141
<li>Validating that all installation accounts have proper data</li>
4242
<li>Testing Octokit authentication for each installation</li>
4343
<li>Listing all organization names (account.login) available</li>
44+
<li>Counting repositories for each GitHub App installation</li>
4445
<li>Verifying account types and permissions</li>
4546
<li>Providing detailed error information for troubleshooting</li>
4647
</ul>
@@ -84,13 +85,19 @@ import { DiagnosticsResponse } from '../../types/diagnostics.types';
8485
<div class="stat-value">{{ getSuccessRate() }}%</div>
8586
<div class="stat-label">Success Rate</div>
8687
</div>
88+
<div class="stat">
89+
<div class="stat-value" [class.success]="lastResult.summary.totalRepositories > 0">
90+
{{ lastResult.summary.totalRepositories }}
91+
</div>
92+
<div class="stat-label">Total Repositories</div>
93+
</div>
8794
</div>
8895
8996
<div class="organizations" *ngIf="lastResult.summary.organizationNames.length > 0">
9097
<h4>Organizations Found:</h4>
9198
<div class="org-list">
9299
<span class="org-chip" *ngFor="let org of lastResult.summary.organizationNames">
93-
{{ org }}
100+
{{ org }} ({{ getRepositoryCount(org) }})
94101
</span>
95102
</div>
96103
</div>
@@ -232,6 +239,11 @@ export class MainDiagnosticsComponent {
232239
return Math.round((this.lastResult.summary.validInstallations / this.lastResult.totalInstallations) * 100);
233240
}
234241

242+
getRepositoryCount(orgName: string): number {
243+
if (!this.lastResult || !this.lastResult.summary.repositoryCounts) return 0;
244+
return this.lastResult.summary.repositoryCounts[orgName] || 0;
245+
}
246+
235247
showFullDetails(): void {
236248
this.dialog.open(InstallationDiagnosticsDialogComponent, {
237249
width: '90vw',
@@ -282,6 +294,7 @@ export class MainDiagnosticsComponent {
282294
<p><strong>Valid:</strong> {{ data.summary.validInstallations }}</p>
283295
<p><strong>Invalid:</strong> {{ data.summary.invalidInstallations }}</p>
284296
<p><strong>Success Rate:</strong> {{ getSuccessRate() }}%</p>
297+
<p><strong>Total Repositories:</strong> {{ data.summary.totalRepositories }}</p>
285298
</mat-card-content>
286299
</mat-card>
287300
</div>
@@ -304,7 +317,7 @@ export class MainDiagnosticsComponent {
304317
</mat-card-header>
305318
<mat-card-content>
306319
<mat-chip-set>
307-
<mat-chip *ngFor="let org of data.summary.organizationNames">{{ org }}</mat-chip>
320+
<mat-chip *ngFor="let org of data.summary.organizationNames">{{ org }} ({{ getRepositoryCount(org) }} repos)</mat-chip>
308321
</mat-chip-set>
309322
</mat-card-content>
310323
</mat-card>
@@ -361,6 +374,9 @@ export class MainDiagnosticsComponent {
361374
<div class="detail-item">
362375
<strong>Has Octokit:</strong> {{ installation.hasOctokit ? 'Yes' : 'No' }}
363376
</div>
377+
<div class="detail-item">
378+
<strong>Repository Count:</strong> {{ installation.repositoryCount }}
379+
</div>
364380
<div class="detail-item">
365381
<strong>Created:</strong> {{ installation.createdAt | date:'medium' }}
366382
</div>
@@ -469,6 +485,11 @@ export class InstallationDiagnosticsDialogComponent {
469485
return Math.round((this.data.summary.validInstallations / this.data.totalInstallations) * 100);
470486
}
471487

488+
getRepositoryCount(orgName: string): number {
489+
if (!this.data.summary.repositoryCounts) return 0;
490+
return this.data.summary.repositoryCounts[orgName] || 0;
491+
}
492+
472493
downloadDiagnostics(): void {
473494
const dataStr = JSON.stringify(this.data, null, 2);
474495
const dataBlob = new Blob([dataStr], { type: 'application/json' });

frontend/src/app/types/diagnostics.types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface InstallationDiagnostic {
2727
octokitTest: OctokitTestResult | null;
2828
isValid: boolean;
2929
validationErrors: string[];
30+
repositoryCount: number;
3031
}
3132

3233
export interface AppInfo {
@@ -50,5 +51,7 @@ export interface DiagnosticsResponse {
5051
invalidInstallations: number;
5152
organizationNames: string[];
5253
accountTypes: Record<string, number>;
54+
repositoryCounts: Record<string, number>;
55+
totalRepositories: number;
5356
};
5457
}

0 commit comments

Comments
 (0)