@@ -4,6 +4,7 @@ import { NoticeManager } from "./notice-manager";
44
55export class GitHubClient {
66 private octokit : Octokit | null = null ;
7+ private currentUser : string = "" ;
78
89 constructor (
910 private settings : GitHubTrackerSettings ,
@@ -54,7 +55,8 @@ export class GitHubClient {
5455
5556 try {
5657 const response = await this . octokit . rest . users . getAuthenticated ( ) ;
57- return response . data . login ;
58+ this . currentUser = response . data . login ;
59+ return this . currentUser ;
5860 } catch ( error ) {
5961 this . noticeManager . error (
6062 "Error fetching authenticated user" ,
@@ -64,6 +66,13 @@ export class GitHubClient {
6466 }
6567 }
6668
69+ /**
70+ * Get the currently cached authenticated user
71+ */
72+ public getCurrentUser ( ) : string {
73+ return this . currentUser ;
74+ }
75+
6776 /**
6877 * Fetch issues for a repository
6978 */
@@ -403,7 +412,158 @@ export class GitHubClient {
403412 }
404413 }
405414
415+ /**
416+ * Fetch labels for a repository
417+ */
418+ public async fetchRepositoryLabels (
419+ owner : string ,
420+ repo : string ,
421+ ) : Promise < any [ ] > {
422+ if ( ! this . octokit ) {
423+ return [ ] ;
424+ }
425+
426+ try {
427+ let allLabels : any [ ] = [ ] ;
428+ let page = 1 ;
429+ let hasMorePages = true ;
430+
431+ while ( hasMorePages ) {
432+ const response = await this . octokit . rest . issues . listLabelsForRepo ( {
433+ owner,
434+ repo,
435+ per_page : 100 ,
436+ page,
437+ } ) ;
438+
439+ allLabels = [ ...allLabels , ...response . data ] ;
440+ hasMorePages = response . data . length === 100 ;
441+ page ++ ;
442+ }
443+
444+ this . noticeManager . debug (
445+ `Fetched ${ allLabels . length } labels for ${ owner } /${ repo } ` ,
446+ ) ;
447+ return allLabels ;
448+ } catch ( error ) {
449+ this . noticeManager . error (
450+ `Error fetching labels for ${ owner } /${ repo } ` ,
451+ error ,
452+ ) ;
453+ return [ ] ;
454+ }
455+ }
456+
457+ /**
458+ * Fetch repository collaborators/contributors
459+ */
460+ public async fetchRepositoryCollaborators (
461+ owner : string ,
462+ repo : string ,
463+ ) : Promise < any [ ] > {
464+ if ( ! this . octokit ) {
465+ return [ ] ;
466+ }
467+
468+ try {
469+ let allCollaborators : any [ ] = [ ] ;
470+ let page = 1 ;
471+ let hasMorePages = true ;
472+
473+ while ( hasMorePages ) {
474+ const response = await this . octokit . rest . repos . listCollaborators ( {
475+ owner,
476+ repo,
477+ per_page : 100 ,
478+ page,
479+ } ) ;
480+
481+ allCollaborators = [ ...allCollaborators , ...response . data ] ;
482+ hasMorePages = response . data . length === 100 ;
483+ page ++ ;
484+ }
485+
486+ this . noticeManager . debug (
487+ `Fetched ${ allCollaborators . length } collaborators for ${ owner } /${ repo } ` ,
488+ ) ;
489+ return allCollaborators ;
490+ } catch ( error ) {
491+ // If collaborators endpoint fails (permissions), try contributors as fallback
492+ try {
493+ let allContributors : any [ ] = [ ] ;
494+ let page = 1 ;
495+ let hasMorePages = true ;
496+
497+ while ( hasMorePages ) {
498+ const response = await this . octokit . rest . repos . listContributors ( {
499+ owner,
500+ repo,
501+ per_page : 100 ,
502+ page,
503+ } ) ;
504+
505+ allContributors = [ ...allContributors , ...response . data ] ;
506+ hasMorePages = response . data . length === 100 ;
507+ page ++ ;
508+ }
509+
510+ this . noticeManager . debug (
511+ `Fetched ${ allContributors . length } contributors for ${ owner } /${ repo } (fallback)` ,
512+ ) ;
513+ return allContributors ;
514+ } catch ( fallbackError ) {
515+ this . noticeManager . error (
516+ `Error fetching collaborators/contributors for ${ owner } /${ repo } ` ,
517+ fallbackError ,
518+ ) ;
519+ return [ ] ;
520+ }
521+ }
522+ }
523+
524+ /**
525+ * Validate the GitHub token and get its scopes
526+ */
527+ public async validateToken ( ) : Promise < { valid : boolean ; scopes : string [ ] ; user ?: string } > {
528+ if ( ! this . octokit ) {
529+ return { valid : false , scopes : [ ] } ;
530+ }
531+
532+ try {
533+ const response = await this . octokit . rest . users . getAuthenticated ( ) ;
534+ const scopes = response . headers [ 'x-oauth-scopes' ] ?. split ( ', ' ) || [ ] ;
535+ return {
536+ valid : true ,
537+ scopes,
538+ user : response . data . login
539+ } ;
540+ } catch ( error ) {
541+ return { valid : false , scopes : [ ] } ;
542+ }
543+ }
544+
545+ /**
546+ * Get current rate limit information
547+ */
548+ public async getRateLimit ( ) : Promise < { remaining : number ; limit : number ; reset : Date } | null > {
549+ if ( ! this . octokit ) {
550+ return null ;
551+ }
552+
553+ try {
554+ const response = await this . octokit . rest . rateLimit . get ( ) ;
555+ return {
556+ remaining : response . data . rate . remaining ,
557+ limit : response . data . rate . limit ,
558+ reset : new Date ( response . data . rate . reset * 1000 )
559+ } ;
560+ } catch ( error ) {
561+ return null ;
562+ }
563+ }
564+
406565 public dispose ( ) : void {
407566 this . octokit = null ;
567+ this . currentUser = "" ;
408568 }
409569}
0 commit comments