Skip to content

Commit 09894a5

Browse files
Add exclude.readOnly and exclude.hidden to gerrit connection config (#280)
1 parent 1507364 commit 09894a5

File tree

10 files changed

+149
-15
lines changed

10 files changed

+149
-15
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Added `exclude.readOnly` and `exclude.hidden` options to Gerrit connection config. [#280](https://github.com/sourcebot-dev/sourcebot/pull/280)
12+
1013
## [3.1.1] - 2025-04-28
1114

1215
### Changed

docs/docs/connections/gerrit.mdx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ To connect to a gerrit instance, provide the `url` property to your config:
5151
"projects": [
5252
"project1/foo-project",
5353
"project2/sub-project/some-sub-folder/**"
54-
]
54+
],
55+
56+
// projects that have state READ_ONLY
57+
"readOnly": true,
58+
59+
// projects that have state HIDDEN
60+
"hidden": true
5561
}
5662
}
5763
```
@@ -110,6 +116,16 @@ To connect to a gerrit instance, provide the `url` property to your config:
110116
]
111117
],
112118
"description": "List of specific projects to exclude from syncing."
119+
},
120+
"readOnly": {
121+
"type": "boolean",
122+
"default": false,
123+
"description": "Exclude read-only projects from syncing."
124+
},
125+
"hidden": {
126+
"type": "boolean",
127+
"default": false,
128+
"description": "Exclude hidden projects from syncing."
113129
}
114130
},
115131
"additionalProperties": false

packages/backend/src/gerrit.ts

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import fetch from 'cross-fetch';
2-
import { GerritConfig } from "@sourcebot/schemas/v2/index.type"
2+
import { GerritConnectionConfig } from "@sourcebot/schemas/v3/index.type"
33
import { createLogger } from './logger.js';
44
import micromatch from "micromatch";
55
import { measure, fetchWithRetry } from './utils.js';
@@ -12,16 +12,19 @@ interface GerritProjects {
1212
[projectName: string]: GerritProjectInfo;
1313
}
1414

15+
// https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#:~:text=date%20upon%20submit.-,state,-optional
16+
type GerritProjectState = 'ACTIVE' | 'READ_ONLY' | 'HIDDEN';
17+
1518
interface GerritProjectInfo {
1619
id: string;
17-
state?: string;
20+
state?: GerritProjectState;
1821
web_links?: GerritWebLink[];
1922
}
2023

2124
interface GerritProject {
2225
name: string;
2326
id: string;
24-
state?: string;
27+
state?: GerritProjectState;
2528
web_links?: GerritWebLink[];
2629
}
2730

@@ -32,7 +35,7 @@ interface GerritWebLink {
3235

3336
const logger = createLogger('Gerrit');
3437

35-
export const getGerritReposFromConfig = async (config: GerritConfig): Promise<GerritProject[]> => {
38+
export const getGerritReposFromConfig = async (config: GerritConnectionConfig): Promise<GerritProject[]> => {
3639
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
3740
const hostname = new URL(config.url).hostname;
3841

@@ -57,24 +60,24 @@ export const getGerritReposFromConfig = async (config: GerritConfig): Promise<Ge
5760
throw e;
5861
}
5962

60-
// exclude "All-Projects" and "All-Users" projects
61-
const excludedProjects = ['All-Projects', 'All-Users', 'All-Avatars', 'All-Archived-Projects'];
62-
projects = projects.filter(project => !excludedProjects.includes(project.name));
63-
6463
// include repos by glob if specified in config
6564
if (config.projects) {
6665
projects = projects.filter((project) => {
6766
return micromatch.isMatch(project.name, config.projects!);
6867
});
6968
}
70-
71-
if (config.exclude && config.exclude.projects) {
72-
projects = projects.filter((project) => {
73-
return !micromatch.isMatch(project.name, config.exclude!.projects!);
69+
70+
projects = projects
71+
.filter((project) => {
72+
const isExcluded = shouldExcludeProject({
73+
project,
74+
exclude: config.exclude,
75+
});
76+
77+
return !isExcluded;
7478
});
75-
}
7679

77-
logger.debug(`Fetched ${Object.keys(projects).length} projects in ${durationMs}ms.`);
80+
logger.debug(`Fetched ${projects.length} projects in ${durationMs}ms.`);
7881
return projects;
7982
};
8083

@@ -137,3 +140,51 @@ const fetchAllProjects = async (url: string): Promise<GerritProject[]> => {
137140

138141
return allProjects;
139142
};
143+
144+
const shouldExcludeProject = ({
145+
project,
146+
exclude,
147+
}: {
148+
project: GerritProject,
149+
exclude?: GerritConnectionConfig['exclude'],
150+
}) => {
151+
let reason = '';
152+
153+
const shouldExclude = (() => {
154+
if ([
155+
'All-Projects',
156+
'All-Users',
157+
'All-Avatars',
158+
'All-Archived-Projects'
159+
].includes(project.name)) {
160+
reason = `Project is a special project.`;
161+
return true;
162+
}
163+
164+
if (!!exclude?.readOnly && project.state === 'READ_ONLY') {
165+
reason = `\`exclude.readOnly\` is true`;
166+
return true;
167+
}
168+
169+
if (!!exclude?.hidden && project.state === 'HIDDEN') {
170+
reason = `\`exclude.hidden\` is true`;
171+
return true;
172+
}
173+
174+
if (exclude?.projects) {
175+
if (micromatch.isMatch(project.name, exclude.projects)) {
176+
reason = `\`exclude.projects\` contains ${project.name}`;
177+
return true;
178+
}
179+
}
180+
181+
return false;
182+
})();
183+
184+
if (shouldExclude) {
185+
logger.debug(`Excluding project ${project.name}. Reason: ${reason}`);
186+
return true;
187+
}
188+
189+
return false;
190+
}

packages/schemas/src/v3/connection.schema.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,16 @@ const schema = {
494494
]
495495
],
496496
"description": "List of specific projects to exclude from syncing."
497+
},
498+
"readOnly": {
499+
"type": "boolean",
500+
"default": false,
501+
"description": "Exclude read-only projects from syncing."
502+
},
503+
"hidden": {
504+
"type": "boolean",
505+
"default": false,
506+
"description": "Exclude hidden projects from syncing."
497507
}
498508
},
499509
"additionalProperties": false

packages/schemas/src/v3/connection.type.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ export interface GerritConnectionConfig {
234234
* List of specific projects to exclude from syncing.
235235
*/
236236
projects?: string[];
237+
/**
238+
* Exclude read-only projects from syncing.
239+
*/
240+
readOnly?: boolean;
241+
/**
242+
* Exclude hidden projects from syncing.
243+
*/
244+
hidden?: boolean;
237245
};
238246
}
239247
export interface BitbucketConnectionConfig {

packages/schemas/src/v3/gerrit.schema.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ const schema = {
4545
]
4646
],
4747
"description": "List of specific projects to exclude from syncing."
48+
},
49+
"readOnly": {
50+
"type": "boolean",
51+
"default": false,
52+
"description": "Exclude read-only projects from syncing."
53+
},
54+
"hidden": {
55+
"type": "boolean",
56+
"default": false,
57+
"description": "Exclude hidden projects from syncing."
4858
}
4959
},
5060
"additionalProperties": false

packages/schemas/src/v3/gerrit.type.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,13 @@ export interface GerritConnectionConfig {
1818
* List of specific projects to exclude from syncing.
1919
*/
2020
projects?: string[];
21+
/**
22+
* Exclude read-only projects from syncing.
23+
*/
24+
readOnly?: boolean;
25+
/**
26+
* Exclude hidden projects from syncing.
27+
*/
28+
hidden?: boolean;
2129
};
2230
}

packages/schemas/src/v3/index.schema.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,16 @@ const schema = {
623623
]
624624
],
625625
"description": "List of specific projects to exclude from syncing."
626+
},
627+
"readOnly": {
628+
"type": "boolean",
629+
"default": false,
630+
"description": "Exclude read-only projects from syncing."
631+
},
632+
"hidden": {
633+
"type": "boolean",
634+
"default": false,
635+
"description": "Exclude hidden projects from syncing."
626636
}
627637
},
628638
"additionalProperties": false

packages/schemas/src/v3/index.type.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,14 @@ export interface GerritConnectionConfig {
329329
* List of specific projects to exclude from syncing.
330330
*/
331331
projects?: string[];
332+
/**
333+
* Exclude read-only projects from syncing.
334+
*/
335+
readOnly?: boolean;
336+
/**
337+
* Exclude hidden projects from syncing.
338+
*/
339+
hidden?: boolean;
332340
};
333341
}
334342
export interface BitbucketConnectionConfig {

schemas/v3/gerrit.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
]
4545
],
4646
"description": "List of specific projects to exclude from syncing."
47+
},
48+
"readOnly": {
49+
"type": "boolean",
50+
"default": false,
51+
"description": "Exclude read-only projects from syncing."
52+
},
53+
"hidden": {
54+
"type": "boolean",
55+
"default": false,
56+
"description": "Exclude hidden projects from syncing."
4757
}
4858
},
4959
"additionalProperties": false

0 commit comments

Comments
 (0)