1
1
import fetch from 'cross-fetch' ;
2
2
import { GerritConfig } from "@sourcebot/schemas/v2/index.type"
3
- import { AppContext , GitRepository } from './types.js' ;
4
3
import { createLogger } from './logger.js' ;
5
- import path from 'path' ;
4
+ import micromatch from "micromatch" ;
6
5
import { measure , marshalBool , excludeReposByName , includeReposByName } from './utils.js' ;
7
6
8
7
// https://gerrit-review.googlesource.com/Documentation/rest-api.html
@@ -16,19 +15,26 @@ interface GerritProjectInfo {
16
15
web_links ?: GerritWebLink [ ] ;
17
16
}
18
17
18
+ interface GerritProject {
19
+ name : string ;
20
+ id : string ;
21
+ state ?: string ;
22
+ web_links ?: GerritWebLink [ ] ;
23
+ }
24
+
19
25
interface GerritWebLink {
20
26
name : string ;
21
27
url : string ;
22
28
}
23
29
24
30
const logger = createLogger ( 'Gerrit' ) ;
25
31
26
- export const getGerritReposFromConfig = async ( config : GerritConfig , ctx : AppContext ) : Promise < GitRepository [ ] > => {
32
+ export const getGerritReposFromConfig = async ( config : GerritConfig ) : Promise < GerritProject [ ] > => {
27
33
28
34
const url = config . url . endsWith ( '/' ) ? config . url : `${ config . url } /` ;
29
35
const hostname = new URL ( config . url ) . hostname ;
30
36
31
- const { durationMs, data : projects } = await measure ( async ( ) => {
37
+ let { durationMs, data : projects } = await measure ( async ( ) => {
32
38
try {
33
39
return fetchAllProjects ( url )
34
40
} catch ( err ) {
@@ -42,67 +48,29 @@ export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppCon
42
48
}
43
49
44
50
// 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
+
91
54
// include repos by glob if specified in config
92
55
if ( config . projects ) {
93
- repos = includeReposByName ( repos , config . projects ) ;
56
+ projects = projects . filter ( ( project ) => {
57
+ return micromatch . isMatch ( project . name , config . projects ! ) ;
58
+ } ) ;
94
59
}
95
-
60
+
96
61
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
+ } ) ;
98
65
}
99
66
100
- return repos ;
67
+ logger . debug ( `Fetched ${ Object . keys ( projects ) . length } projects in ${ durationMs } ms.` ) ;
68
+ return projects ;
101
69
} ;
102
70
103
- const fetchAllProjects = async ( url : string ) : Promise < GerritProjects > => {
71
+ const fetchAllProjects = async ( url : string ) : Promise < GerritProject [ ] > => {
104
72
const projectsEndpoint = `${ url } projects/` ;
105
- let allProjects : GerritProjects = { } ;
73
+ let allProjects : GerritProject [ ] = [ ] ;
106
74
let start = 0 ; // Start offset for pagination
107
75
let hasMoreProjects = true ;
108
76
@@ -119,8 +87,15 @@ const fetchAllProjects = async (url: string): Promise<GerritProjects> => {
119
87
const jsonText = text . replace ( ")]}'\n" , '' ) ; // Remove XSSI protection prefix
120
88
const data : GerritProjects = JSON . parse ( jsonText ) ;
121
89
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
+ }
124
99
125
100
// Check if there are more projects to fetch
126
101
hasMoreProjects = Object . values ( data ) . some (
0 commit comments