@@ -53,6 +53,7 @@ type GitRemoteInfoContext = {
5353
5454export class ParserIncludes {
5555 private static count : number = 0 ;
56+ private static gitRemoteInfoCache : Record < string , string > = { } ;
5657
5758 static resetCount ( ) : void {
5859 this . count = 0 ;
@@ -114,13 +115,13 @@ export class ParserIncludes {
114115 promises . push ( this . downloadIncludeRemote ( cwd , stateDir , value [ "remote" ] , fetchIncludes , writeStreams ) ) ;
115116 } else if ( value [ "component" ] ) {
116117 const component = this . parseIncludeComponent ( value [ "component" ] , gitData ) ;
117- componentParseCache . set ( index , component ) ;
118- if ( ! component . isLocal )
119- {
120- promises . push ( this . downloadIncludeComponent ( opts , component . projectPath , component . effectiveRef , component . componentPath ) ) ;
121- }
118+ promises . push ( ( async ( componentParseCache : Map < number , ParsedComponent > , component : ParsedComponent , opts : ParserIncludesInitOptions ) => {
119+ if ( ! component . isLocal ) {
120+ await this . downloadIncludeComponent ( opts , component . projectPath , component . effectiveRef , component . componentPath ) ;
121+ }
122+ componentParseCache . set ( index , component ) ;
123+ } ) ( componentParseCache , component , opts ) ) ;
122124 }
123-
124125 }
125126
126127 await Promise . all ( promises ) ;
@@ -251,13 +252,30 @@ export class ParserIncludes {
251252 } ;
252253 }
253254
255+ static getGitRemoteInfo ( ctx : GitRemoteInfoContext , ...args : string [ ] ) : string {
256+ const cmdArgs = [ "git" , "ls-remote" , ...args ] ;
257+ if ( ctx . gitData . remote . schema == "git" || ctx . gitData . remote . schema == "ssh" ) {
258+ cmdArgs . push ( `git@${ ctx . domain } :${ ctx . projectPath } ` ) ;
259+ } else {
260+ cmdArgs . push ( `${ ctx . gitData . remote . schema } ://${ ctx . domain } :${ ctx . port ?? 443 } /${ ctx . projectPath } .git` ) ;
261+ }
262+ const cmdStr = cmdArgs . join ( " " ) ;
263+ let info = this . gitRemoteInfoCache [ cmdStr ] ;
264+ if ( ! ( cmdStr in this . gitRemoteInfoCache ) ) {
265+ info = Utils . syncSpawn ( cmdArgs ) . stdout ;
266+ this . gitRemoteInfoCache [ cmdStr ] = info ;
267+ }
268+ return info ;
269+ } ;
270+
254271 static parseIncludeComponent ( component : string , gitData : GitData ) : ParsedComponent {
255272 assert ( ! component . includes ( "://" ) , `This GitLab CI configuration is invalid: component: \`${ component } \` should not contain protocol` ) ;
256273 const pattern = / (?< domain > [ ^ / : \s ] + ) ( : (?< port > \d + ) ) ? \/ (?< projectPath > .+ ) \/ (?< componentName > [ ^ @ ] + ) @ (?< ref > .+ ) / ; // https://regexr.com/7v7hm
257274 const gitRemoteMatch = pattern . exec ( component ) ;
258275 if ( gitRemoteMatch ?. groups == null ) throw new Error ( `This is a bug, please create a github issue if this is something you're expecting to work. input: ${ component } ` ) ;
259276 const { domain, projectPath, port, componentName, ref} = gitRemoteMatch . groups ;
260277 const isLocalComponent = projectPath === `${ gitData . remote . group } /${ gitData . remote . project } ` && ref === gitData . commit . SHA ;
278+ const parserIncludes = this ; // eslint-disable-line @typescript-eslint/no-this-alias
261279 return {
262280 _cache : {
263281 version : undefined ,
@@ -279,7 +297,7 @@ export class ParserIncludes {
279297 const semanticVersionRangesPattern = / ^ \d + ( \. \d + ) ? $ / ;
280298 if ( this . reference == "~latest" || semanticVersionRangesPattern . test ( this . reference ) ) {
281299 // https://docs.gitlab.com/ci/components/#semantic-version-ranges
282- const stdout = getGitRemoteInfo ( this , "--tags" ) ;
300+ const stdout = parserIncludes . getGitRemoteInfo ( this , "--tags" ) ;
283301 const tags = stdout . split ( "\n" ) . map ( line => line . split ( "\t" ) [ 1 ] . split ( "/" ) [ 2 ] ) ;
284302 const version = resolveSemanticVersionRange ( this . reference , tags ) ;
285303 assert ( version , `This GitLab CI configuration is invalid: component: \`${ this . name } \` - The reference (${ this . reference } ) is invalid` ) ;
@@ -305,7 +323,7 @@ export class ParserIncludes {
305323 // effectiveRef may already be a sha, if so return it directly
306324 this . _cache . sha = this . effectiveRef ;
307325 } else {
308- const stdout = getGitRemoteInfo ( this ) ;
326+ const stdout = parserIncludes . getGitRemoteInfo ( this ) ;
309327 const lines = stdout . split ( "\n" ) ;
310328 // annotated tags: prefer the deref'd commit sha (refs/tags/x^{})
311329 const match = lines . find ( line => line . endsWith ( `refs/tags/${ this . effectiveRef } ^{}` ) ) ??
@@ -505,13 +523,3 @@ export async function resolveIncludeLocal (pattern: string, cwd: string) {
505523 const re2js = RE2JS . compile ( `^${ pattern } ` ) ;
506524 return repoFiles . filter ( ( f : any ) => re2js . matches ( f ) ) ;
507525}
508-
509- export function getGitRemoteInfo ( ctx : GitRemoteInfoContext , ...args : string [ ] ) {
510- const cmdArgs = [ "git" , "ls-remote" , ...args ] ;
511- if ( ctx . gitData . remote . schema == "git" || ctx . gitData . remote . schema == "ssh" ) {
512- cmdArgs . push ( `git@${ ctx . domain } :${ ctx . projectPath } ` ) ;
513- } else {
514- cmdArgs . push ( `${ ctx . gitData . remote . schema } ://${ ctx . domain } :${ ctx . port ?? 443 } /${ ctx . projectPath } .git` ) ;
515- }
516- return Utils . syncSpawn ( cmdArgs ) . stdout ;
517- }
0 commit comments