44 *--------------------------------------------------------------------------------------------*/
55
66import { AuthProvider , GitHubServerType } from './authentication' ;
7+ import Logger from './logger' ;
78import { Protocol } from './protocol' ;
89import { Repository } from '../api/api' ;
910import { getEnterpriseUri , isEnterprise } from '../github/utils' ;
@@ -74,6 +75,54 @@ export function parseRemote(remoteName: string, url: string, originalProtocol?:
7475 return null ;
7576}
7677
78+ /**
79+ * Resolves git URL aliases by applying insteadOf substitutions from git config.
80+ * For example, if git config has:
81+ 82+ * insteadOf = "gh:"
83+ * Then "gh:user/repo" will be resolved to "[email protected] :user/repo" 84+ *
85+ * @param url The URL to resolve
86+ * @param repository The repository to get config from
87+ * @returns The resolved URL, or the original URL if no substitution found
88+ */
89+ async function resolveGitUrl ( url : string , repository : Repository ) : Promise < string > {
90+ try {
91+ // Get all git config entries
92+ const configs = await repository . getConfigs ( ) ;
93+
94+ // Find all url.*.insteadOf entries
95+ const urlSubstitutions : { prefix : string ; replacement : string } [ ] = [ ] ;
96+
97+ for ( const config of configs ) {
98+ // Match patterns like "url.https://github.com/.insteadOf" or "[email protected] :.insteadOf" 99+ const match = config . key . match ( / ^ u r l \. ( .+ ) \. i n s t e a d o f $ / i) ;
100+ if ( match ) {
101+ const replacement = match [ 1 ] ;
102+ const prefix = config . value ;
103+ urlSubstitutions . push ( { prefix, replacement } ) ;
104+ }
105+ }
106+
107+ // Sort by prefix length (longest first) to handle overlapping prefixes correctly
108+ urlSubstitutions . sort ( ( a , b ) => b . prefix . length - a . prefix . length ) ;
109+
110+ // Apply the first matching substitution
111+ for ( const { prefix, replacement } of urlSubstitutions ) {
112+ if ( url . startsWith ( prefix ) ) {
113+ const resolvedUrl = replacement + url . substring ( prefix . length ) ;
114+ Logger . appendLine ( `Resolved git URL alias: "${ url } " -> "${ resolvedUrl } "` , 'Remote' ) ;
115+ return resolvedUrl ;
116+ }
117+ }
118+ } catch ( error ) {
119+ Logger . error ( `Failed to resolve git URL aliases for "${ url } ": ${ error } ` , 'Remote' ) ;
120+ }
121+
122+ // No substitution found or error occurred, return original URL
123+ return url ;
124+ }
125+
77126export function parseRepositoryRemotes ( repository : Repository ) : Remote [ ] {
78127 const remotes : Remote [ ] = [ ] ;
79128 for ( const r of repository . state . remotes ) {
@@ -94,6 +143,38 @@ export function parseRepositoryRemotes(repository: Repository): Remote[] {
94143 return remotes ;
95144}
96145
146+ /**
147+ * Asynchronously parses repository remotes with git URL alias resolution.
148+ * This version resolves git URL aliases (e.g., "gh:" -> "[email protected] :") before parsing. 149+ * Use this version when you need accurate remote parsing with alias resolution.
150+ *
151+ * @param repository The repository to parse remotes from
152+ * @returns Promise resolving to array of Remote objects
153+ */
154+ export async function parseRepositoryRemotesAsync ( repository : Repository ) : Promise < Remote [ ] > {
155+ const remotes : Remote [ ] = [ ] ;
156+ for ( const r of repository . state . remotes ) {
157+ const urls : string [ ] = [ ] ;
158+ if ( r . fetchUrl ) {
159+ // Resolve git URL aliases before parsing
160+ const resolvedUrl = await resolveGitUrl ( r . fetchUrl , repository ) ;
161+ urls . push ( resolvedUrl ) ;
162+ }
163+ if ( r . pushUrl && r . pushUrl !== r . fetchUrl ) {
164+ // Resolve git URL aliases before parsing
165+ const resolvedUrl = await resolveGitUrl ( r . pushUrl , repository ) ;
166+ urls . push ( resolvedUrl ) ;
167+ }
168+ urls . forEach ( url => {
169+ const remote = parseRemote ( r . name , url ) ;
170+ if ( remote ) {
171+ remotes . push ( remote ) ;
172+ }
173+ } ) ;
174+ }
175+ return remotes ;
176+ }
177+
97178export class GitHubRemote extends Remote {
98179 static remoteAsGitHub ( remote : Remote , githubServerType : GitHubServerType ) : GitHubRemote {
99180 return new GitHubRemote ( remote . remoteName , remote . url , remote . gitProtocol , githubServerType ) ;
0 commit comments