mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 20:35:24 +00:00
* Basic gerrit sync with working gitiles web-links functionality This adds basic support for gerrit repo code host syncing. Gerrit uses gitiles plugin for code browsing (in most cases). It may be usefull to allow users to provide their own web code-browsing url templates in the future. * Add gerrit readme update * Remove config arg from gerrit fetchAllProjects * Remove example urls * Resolve comments
109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
import fetch from 'cross-fetch';
|
|
import { GerritConfig } from './schemas/v2.js';
|
|
import { AppContext, GitRepository } from './types.js';
|
|
import { createLogger } from './logger.js';
|
|
import path from 'path';
|
|
import { measure, marshalBool, excludeReposByName, includeReposByName } from './utils.js';
|
|
|
|
// https://gerrit-review.googlesource.com/Documentation/rest-api.html
|
|
interface GerritProjects {
|
|
[projectName: string]: GerritProjectInfo;
|
|
}
|
|
|
|
interface GerritProjectInfo {
|
|
id: string;
|
|
state?: string;
|
|
web_links?: GerritWebLink[];
|
|
}
|
|
|
|
interface GerritWebLink {
|
|
name: string;
|
|
url: string;
|
|
}
|
|
|
|
const logger = createLogger('Gerrit');
|
|
|
|
export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppContext) => {
|
|
|
|
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
|
|
const hostname = new URL(config.url).hostname;
|
|
|
|
const { durationMs, data: projects } = await measure(() =>
|
|
fetchAllProjects(url)
|
|
);
|
|
|
|
// exclude "All-Projects" and "All-Users" projects
|
|
delete projects['All-Projects'];
|
|
delete projects['All-Users'];
|
|
|
|
logger.debug(`Fetched ${Object.keys(projects).length} projects in ${durationMs}ms.`);
|
|
|
|
let repos: GitRepository[] = Object.keys(projects).map((projectName) => {
|
|
const project = projects[projectName];
|
|
let webUrl = "https://www.gerritcodereview.com/";
|
|
// Gerrit projects can have multiple web links; use the first one
|
|
if (project.web_links) {
|
|
const webLink = project.web_links[0];
|
|
if (webLink) {
|
|
webUrl = webLink.url;
|
|
}
|
|
}
|
|
const repoId = `${hostname}/${projectName}`;
|
|
const repoPath = path.resolve(path.join(ctx.reposPath, `${repoId}.git`));
|
|
|
|
const cloneUrl = `${url}${encodeURIComponent(projectName)}`;
|
|
|
|
return {
|
|
vcs: 'git',
|
|
codeHost: 'gerrit',
|
|
name: projectName,
|
|
id: repoId,
|
|
cloneUrl: cloneUrl,
|
|
path: repoPath,
|
|
isStale: false, // Gerrit projects are typically not stale
|
|
isFork: false, // Gerrit doesn't have forks in the same way as GitHub
|
|
isArchived: false,
|
|
gitConfigMetadata: {
|
|
// Gerrit uses Gitiles for web UI. This can sometimes be "browse" type in zoekt
|
|
'zoekt.web-url-type': 'gitiles',
|
|
'zoekt.web-url': webUrl,
|
|
'zoekt.name': repoId,
|
|
'zoekt.archived': marshalBool(false),
|
|
'zoekt.fork': marshalBool(false),
|
|
'zoekt.public': marshalBool(true), // Assuming projects are public; adjust as needed
|
|
},
|
|
branches: [],
|
|
tags: []
|
|
} satisfies GitRepository;
|
|
});
|
|
|
|
// include repos by glob if specified in config
|
|
if (config.projects) {
|
|
repos = includeReposByName(repos, config.projects);
|
|
}
|
|
|
|
if (config.exclude && config.exclude.projects) {
|
|
repos = excludeReposByName(repos, config.exclude.projects);
|
|
}
|
|
|
|
return repos;
|
|
};
|
|
|
|
const fetchAllProjects = async (url: string): Promise<GerritProjects> => {
|
|
|
|
const projectsEndpoint = `${url}projects/`;
|
|
logger.debug(`Fetching projects from Gerrit at ${projectsEndpoint}...`);
|
|
const response = await fetch(projectsEndpoint);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch projects from Gerrit: ${response.statusText}`);
|
|
}
|
|
|
|
const text = await response.text();
|
|
|
|
// Gerrit prepends ")]}'\n" to prevent XSSI attacks; remove it
|
|
// https://gerrit-review.googlesource.com/Documentation/rest-api.html
|
|
const jsonText = text.replace(")]}'\n", '');
|
|
const data = JSON.parse(jsonText);
|
|
return data;
|
|
};
|