11import fetch from 'cross-fetch' ;
22import { GerritConfig } from "@sourcebot/schemas/v2/index.type"
3- import { AppContext , GitRepository } from './types.js' ;
43import { createLogger } from './logger.js' ;
5- import path from 'path' ;
4+ import micromatch from "micromatch" ;
65import { measure , marshalBool , excludeReposByName , includeReposByName } from './utils.js' ;
76
87// https://gerrit-review.googlesource.com/Documentation/rest-api.html
@@ -16,19 +15,26 @@ interface GerritProjectInfo {
1615 web_links ?: GerritWebLink [ ] ;
1716}
1817
18+ interface GerritProject {
19+ name : string ;
20+ id : string ;
21+ state ?: string ;
22+ web_links ?: GerritWebLink [ ] ;
23+ }
24+
1925interface GerritWebLink {
2026 name : string ;
2127 url : string ;
2228}
2329
2430const logger = createLogger ( 'Gerrit' ) ;
2531
26- export const getGerritReposFromConfig = async ( config : GerritConfig , ctx : AppContext ) : Promise < GitRepository [ ] > => {
32+ export const getGerritReposFromConfig = async ( config : GerritConfig ) : Promise < GerritProject [ ] > => {
2733
2834 const url = config . url . endsWith ( '/' ) ? config . url : `${ config . url } /` ;
2935 const hostname = new URL ( config . url ) . hostname ;
3036
31- const { durationMs, data : projects } = await measure ( async ( ) => {
37+ let { durationMs, data : projects } = await measure ( async ( ) => {
3238 try {
3339 return fetchAllProjects ( url )
3440 } catch ( err ) {
@@ -42,67 +48,29 @@ export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppCon
4248 }
4349
4450 // exclude "All-Projects" and "All-Users" projects
45- delete projects [ 'All-Projects' ] ;
46- delete projects [ 'All-Users' ] ;
47- delete projects [ 'All-Avatars' ]
48- delete projects [ 'All-Archived-Projects' ]
49-
50- logger . debug ( `Fetched ${ Object . keys ( projects ) . length } projects in ${ durationMs } ms.` ) ;
51-
52- let repos : GitRepository [ ] = Object . keys ( projects ) . map ( ( projectName ) => {
53- const project = projects [ projectName ] ;
54- let webUrl = "https://www.gerritcodereview.com/" ;
55- // Gerrit projects can have multiple web links; use the first one
56- if ( project . web_links ) {
57- const webLink = project . web_links [ 0 ] ;
58- if ( webLink ) {
59- webUrl = webLink . url ;
60- }
61- }
62- const repoId = `${ hostname } /${ projectName } ` ;
63- const repoPath = path . resolve ( path . join ( ctx . reposPath , `${ repoId } .git` ) ) ;
64-
65- const cloneUrl = `${ url } ${ encodeURIComponent ( projectName ) } ` ;
66-
67- return {
68- vcs : 'git' ,
69- codeHost : 'gerrit' ,
70- name : projectName ,
71- id : repoId ,
72- cloneUrl : cloneUrl ,
73- path : repoPath ,
74- isStale : false , // Gerrit projects are typically not stale
75- isFork : false , // Gerrit doesn't have forks in the same way as GitHub
76- isArchived : false ,
77- gitConfigMetadata : {
78- // Gerrit uses Gitiles for web UI. This can sometimes be "browse" type in zoekt
79- 'zoekt.web-url-type' : 'gitiles' ,
80- 'zoekt.web-url' : webUrl ,
81- 'zoekt.name' : repoId ,
82- 'zoekt.archived' : marshalBool ( false ) ,
83- 'zoekt.fork' : marshalBool ( false ) ,
84- 'zoekt.public' : marshalBool ( true ) , // Assuming projects are public; adjust as needed
85- } ,
86- branches : [ ] ,
87- tags : [ ]
88- } satisfies GitRepository ;
89- } ) ;
90-
51+ const excludedProjects = [ 'All-Projects' , 'All-Users' , 'All-Avatars' , 'All-Archived-Projects' ] ;
52+ projects = projects . filter ( project => ! excludedProjects . includes ( project . name ) ) ;
53+
9154 // include repos by glob if specified in config
9255 if ( config . projects ) {
93- repos = includeReposByName ( repos , config . projects ) ;
56+ projects = projects . filter ( ( project ) => {
57+ return micromatch . isMatch ( project . name , config . projects ! ) ;
58+ } ) ;
9459 }
95-
60+
9661 if ( config . exclude && config . exclude . projects ) {
97- repos = excludeReposByName ( repos , config . exclude . projects ) ;
62+ projects = projects . filter ( ( project ) => {
63+ return ! micromatch . isMatch ( project . name , config . exclude ! . projects ! ) ;
64+ } ) ;
9865 }
9966
100- return repos ;
67+ logger . debug ( `Fetched ${ Object . keys ( projects ) . length } projects in ${ durationMs } ms.` ) ;
68+ return projects ;
10169} ;
10270
103- const fetchAllProjects = async ( url : string ) : Promise < GerritProjects > => {
71+ const fetchAllProjects = async ( url : string ) : Promise < GerritProject [ ] > => {
10472 const projectsEndpoint = `${ url } projects/` ;
105- let allProjects : GerritProjects = { } ;
73+ let allProjects : GerritProject [ ] = [ ] ;
10674 let start = 0 ; // Start offset for pagination
10775 let hasMoreProjects = true ;
10876
@@ -119,8 +87,15 @@ const fetchAllProjects = async (url: string): Promise<GerritProjects> => {
11987 const jsonText = text . replace ( ")]}'\n" , '' ) ; // Remove XSSI protection prefix
12088 const data : GerritProjects = JSON . parse ( jsonText ) ;
12189
122- // Merge the current batch of projects with allProjects
123- Object . assign ( allProjects , data ) ;
90+ // Add fetched projects to allProjects
91+ for ( const [ projectName , projectInfo ] of Object . entries ( data ) ) {
92+ allProjects . push ( {
93+ name : projectName ,
94+ id : projectInfo . id ,
95+ state : projectInfo . state ,
96+ web_links : projectInfo . web_links
97+ } )
98+ }
12499
125100 // Check if there are more projects to fetch
126101 hasMoreProjects = Object . values ( data ) . some (
0 commit comments