import { RemoteSourceProvider , RemoteSource } from './typings/git-base' ; import { getOctokit } from './auth' ; import { Octokit } from '@octokit/rest' ; function parse ( url ) { const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i . exec ( url ) || /^git@github\.com:([^/]+)\/([^/]+)\.git/i . exec ( url ) ; return ( match && { owner : match [ 1 ] , repo : match [ 2 ] } ) ?? undefined ; } function asRemoteSource ( raw ) { return { name : `$(github) ${ raw . full_name }` , description : raw . description || undefined , url : raw . clone_url } ; } export class GithubRemoteSourceProvider implements RemoteSourceProvider { readonly name = 'GitHub' ; readonly icon = 'github' ; readonly supportsQuery = true ; private userReposCache : RemoteSource [ ] = [ ] ; async getRemoteSources ( query ? ) { const octokit = await getOctokit ( ) ; if ( query ) { const repository = parse ( query ) ; if ( repository ) { const raw = await octokit . repos . get ( repository ) ; return [ asRemoteSource ( raw . data ) ] ; } } const all = await Promise . all ( [ this . getQueryRemoteSources ( octokit , query ) , this . getUserRemoteSources ( octokit , query ) , ] ) ; const map = new Map < string , RemoteSource > ( ) ; for ( const group of all ) { for ( const remoteSource of group ) { map . set ( remoteSource . name , remoteSource ) ; } } return [ ... map . values ( ) ] ; } private async getUserRemoteSources ( octokit , query ? ) { if ( ! query ) { const user = await octokit . users . getAuthenticated ( { } ) ; const username = user . data . login ; const res = await octokit . repos . listForUser ( { username , sort : 'updated' , per_page : 100 } ) ; this . userReposCache = res . data . map ( asRemoteSource ) ; } return this . userReposCache ; } private async getQueryRemoteSources ( octokit , query ? ) { if ( ! query ) { return [ ] ; } const raw = await octokit . search . repos ( { q : query , sort : 'stars' } ) ; return raw . data . items . map ( asRemoteSource ) ; } async getBranches ( url ) { const repository = parse ( url ) ; if ( ! repository ) { return [ ] ; } const octokit = await getOctokit ( ) ; const branches = [ ] ; let page = 1 ; while ( true ) { let res = await octokit . repos . listBranches ( { ... repository , per_page : 100 , page } ) ; if ( res . data . length === 0 ) { break ; } branches . push ( ... res . data . map ( b => b . name ) ) ; page ++ ; } const repo = await octokit . repos . get ( repository ) ; const defaultBranch = repo . data . default_branch ; return branches . sort ( ( a , b ) => a === defaultBranch ? - 1 : b === defaultBranch ? 1 : 0 ) ; } }