mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-14 05:15:19 +00:00
add back gitlab, gitea, and gerrit support (#184)
* add non github config definitions * refactor github config compilation to seperate file * add gitlab config compilation * Connection management (#183) * wip gitlab repo sync support * fix gitlab zoekt metadata * add gitea support * add gerrit support * Connection management (#183) * add gerrit config compilation * Connection management (#183) --------- Co-authored-by: Brendan Kellam <bshizzle1234@gmail.com>
This commit is contained in:
parent
e2e5433d20
commit
da33220289
30 changed files with 1576 additions and 213 deletions
|
|
@ -5,8 +5,7 @@ import { ConnectionConfig } from "@sourcebot/schemas/v3/connection.type";
|
||||||
import { createLogger } from "./logger.js";
|
import { createLogger } from "./logger.js";
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
import { marshalBool } from "./utils.js";
|
import { RepoData, compileGithubConfig, compileGitlabConfig, compileGiteaConfig, compileGerritConfig } from "./repoCompileUtils.js";
|
||||||
import { getGitHubReposFromConfig } from "./github.js";
|
|
||||||
|
|
||||||
interface IConnectionManager {
|
interface IConnectionManager {
|
||||||
scheduleConnectionSync: (connection: Connection) => Promise<void>;
|
scheduleConnectionSync: (connection: Connection) => Promise<void>;
|
||||||
|
|
@ -79,64 +78,28 @@ export class ConnectionManager implements IConnectionManager {
|
||||||
// @note: We aren't actually doing anything with this atm.
|
// @note: We aren't actually doing anything with this atm.
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
|
|
||||||
type RepoData = WithRequired<Prisma.RepoCreateInput, 'connections'>;
|
const repoData: RepoData[] = await (async () => {
|
||||||
const repoData: RepoData[] = (
|
switch (config.type) {
|
||||||
await (async () => {
|
case 'github': {
|
||||||
switch (config.type) {
|
return await compileGithubConfig(config, job.data.connectionId, orgId, this.db, abortController);
|
||||||
case 'github': {
|
|
||||||
const gitHubRepos = await getGitHubReposFromConfig(config, orgId, this.db, abortController.signal);
|
|
||||||
const hostUrl = config.url ?? 'https://github.com';
|
|
||||||
const hostname = config.url ? new URL(config.url).hostname : 'github.com';
|
|
||||||
|
|
||||||
return gitHubRepos.map((repo) => {
|
|
||||||
const repoName = `${hostname}/${repo.full_name}`;
|
|
||||||
const cloneUrl = new URL(repo.clone_url!);
|
|
||||||
|
|
||||||
const record: RepoData = {
|
|
||||||
external_id: repo.id.toString(),
|
|
||||||
external_codeHostType: 'github',
|
|
||||||
external_codeHostUrl: hostUrl,
|
|
||||||
cloneUrl: cloneUrl.toString(),
|
|
||||||
imageUrl: repo.owner.avatar_url,
|
|
||||||
name: repoName,
|
|
||||||
isFork: repo.fork,
|
|
||||||
isArchived: !!repo.archived,
|
|
||||||
org: {
|
|
||||||
connect: {
|
|
||||||
id: orgId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
connections: {
|
|
||||||
create: {
|
|
||||||
connectionId: job.data.connectionId,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
'zoekt.web-url-type': 'github',
|
|
||||||
'zoekt.web-url': repo.html_url,
|
|
||||||
'zoekt.name': repoName,
|
|
||||||
'zoekt.github-stars': (repo.stargazers_count ?? 0).toString(),
|
|
||||||
'zoekt.github-watchers': (repo.watchers_count ?? 0).toString(),
|
|
||||||
'zoekt.github-subscribers': (repo.subscribers_count ?? 0).toString(),
|
|
||||||
'zoekt.github-forks': (repo.forks_count ?? 0).toString(),
|
|
||||||
'zoekt.archived': marshalBool(repo.archived),
|
|
||||||
'zoekt.fork': marshalBool(repo.fork),
|
|
||||||
'zoekt.public': marshalBool(repo.private === false)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return record;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case 'gitlab': {
|
|
||||||
// @todo
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})()
|
case 'gitlab': {
|
||||||
)
|
return await compileGitlabConfig(config, job.data.connectionId, orgId, this.db);
|
||||||
|
}
|
||||||
|
case 'gitea': {
|
||||||
|
return await compileGiteaConfig(config, job.data.connectionId, orgId, this.db);
|
||||||
|
}
|
||||||
|
case 'gerrit': {
|
||||||
|
return await compileGerritConfig(config, job.data.connectionId, orgId);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Filter out any duplicates by external_id and external_codeHostUrl.
|
// Filter out any duplicates by external_id and external_codeHostUrl.
|
||||||
.filter((repo, index, self) => {
|
repoData.filter((repo, index, self) => {
|
||||||
return index === self.findIndex(r =>
|
return index === self.findIndex(r =>
|
||||||
r.external_id === repo.external_id &&
|
r.external_id === repo.external_id &&
|
||||||
r.external_codeHostUrl === repo.external_codeHostUrl
|
r.external_codeHostUrl === repo.external_codeHostUrl
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import fetch from 'cross-fetch';
|
import fetch from 'cross-fetch';
|
||||||
import { GerritConfig } from "@sourcebot/schemas/v2/index.type"
|
import { GerritConfig } from "@sourcebot/schemas/v2/index.type"
|
||||||
import { AppContext, GitRepository } from './types.js';
|
|
||||||
import { createLogger } from './logger.js';
|
import { createLogger } from './logger.js';
|
||||||
import path from 'path';
|
import micromatch from "micromatch";
|
||||||
import { measure, marshalBool, excludeReposByName, includeReposByName } from './utils.js';
|
import { measure, marshalBool, excludeReposByName, includeReposByName } from './utils.js';
|
||||||
|
|
||||||
// https://gerrit-review.googlesource.com/Documentation/rest-api.html
|
// https://gerrit-review.googlesource.com/Documentation/rest-api.html
|
||||||
|
|
@ -16,6 +15,13 @@ interface GerritProjectInfo {
|
||||||
web_links?: GerritWebLink[];
|
web_links?: GerritWebLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GerritProject {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
state?: string;
|
||||||
|
web_links?: GerritWebLink[];
|
||||||
|
}
|
||||||
|
|
||||||
interface GerritWebLink {
|
interface GerritWebLink {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
|
@ -23,12 +29,12 @@ interface GerritWebLink {
|
||||||
|
|
||||||
const logger = createLogger('Gerrit');
|
const logger = createLogger('Gerrit');
|
||||||
|
|
||||||
export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppContext): Promise<GitRepository[]> => {
|
export const getGerritReposFromConfig = async (config: GerritConfig): Promise<GerritProject[]> => {
|
||||||
|
|
||||||
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
|
const url = config.url.endsWith('/') ? config.url : `${config.url}/`;
|
||||||
const hostname = new URL(config.url).hostname;
|
const hostname = new URL(config.url).hostname;
|
||||||
|
|
||||||
const { durationMs, data: projects } = await measure(async () => {
|
let { durationMs, data: projects } = await measure(async () => {
|
||||||
try {
|
try {
|
||||||
return fetchAllProjects(url)
|
return fetchAllProjects(url)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -42,67 +48,29 @@ export const getGerritReposFromConfig = async (config: GerritConfig, ctx: AppCon
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclude "All-Projects" and "All-Users" projects
|
// exclude "All-Projects" and "All-Users" projects
|
||||||
delete projects['All-Projects'];
|
const excludedProjects = ['All-Projects', 'All-Users', 'All-Avatars', 'All-Archived-Projects'];
|
||||||
delete projects['All-Users'];
|
projects = projects.filter(project => !excludedProjects.includes(project.name));
|
||||||
delete projects['All-Avatars']
|
|
||||||
delete projects['All-Archived-Projects']
|
|
||||||
|
|
||||||
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
|
// include repos by glob if specified in config
|
||||||
if (config.projects) {
|
if (config.projects) {
|
||||||
repos = includeReposByName(repos, config.projects);
|
projects = projects.filter((project) => {
|
||||||
|
return micromatch.isMatch(project.name, config.projects!);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.exclude && config.exclude.projects) {
|
if (config.exclude && config.exclude.projects) {
|
||||||
repos = excludeReposByName(repos, config.exclude.projects);
|
projects = projects.filter((project) => {
|
||||||
|
return !micromatch.isMatch(project.name, config.exclude!.projects!);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos;
|
logger.debug(`Fetched ${Object.keys(projects).length} projects in ${durationMs}ms.`);
|
||||||
|
return projects;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAllProjects = async (url: string): Promise<GerritProjects> => {
|
const fetchAllProjects = async (url: string): Promise<GerritProject[]> => {
|
||||||
const projectsEndpoint = `${url}projects/`;
|
const projectsEndpoint = `${url}projects/`;
|
||||||
let allProjects: GerritProjects = {};
|
let allProjects: GerritProject[] = [];
|
||||||
let start = 0; // Start offset for pagination
|
let start = 0; // Start offset for pagination
|
||||||
let hasMoreProjects = true;
|
let hasMoreProjects = true;
|
||||||
|
|
||||||
|
|
@ -119,8 +87,15 @@ const fetchAllProjects = async (url: string): Promise<GerritProjects> => {
|
||||||
const jsonText = text.replace(")]}'\n", ''); // Remove XSSI protection prefix
|
const jsonText = text.replace(")]}'\n", ''); // Remove XSSI protection prefix
|
||||||
const data: GerritProjects = JSON.parse(jsonText);
|
const data: GerritProjects = JSON.parse(jsonText);
|
||||||
|
|
||||||
// Merge the current batch of projects with allProjects
|
// Add fetched projects to allProjects
|
||||||
Object.assign(allProjects, data);
|
for (const [projectName, projectInfo] of Object.entries(data)) {
|
||||||
|
allProjects.push({
|
||||||
|
name: projectName,
|
||||||
|
id: projectInfo.id,
|
||||||
|
state: projectInfo.state,
|
||||||
|
web_links: projectInfo.web_links
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there are more projects to fetch
|
// Check if there are more projects to fetch
|
||||||
hasMoreProjects = Object.values(data).some(
|
hasMoreProjects = Object.values(data).some(
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
import { Api, giteaApi, HttpResponse, Repository as GiteaRepository } from 'gitea-js';
|
import { Api, giteaApi, HttpResponse, Repository as GiteaRepository } from 'gitea-js';
|
||||||
import { GiteaConfig } from "@sourcebot/schemas/v2/index.type"
|
import { GiteaConnectionConfig } from '@sourcebot/schemas/v3/gitea.type';
|
||||||
import { excludeArchivedRepos, excludeForkedRepos, excludeReposByName, getTokenFromConfig, marshalBool, measure } from './utils.js';
|
import { getTokenFromConfig, measure } from './utils.js';
|
||||||
import { AppContext, GitRepository } from './types.js';
|
|
||||||
import fetch from 'cross-fetch';
|
import fetch from 'cross-fetch';
|
||||||
import { createLogger } from './logger.js';
|
import { createLogger } from './logger.js';
|
||||||
import path from 'path';
|
|
||||||
import micromatch from 'micromatch';
|
import micromatch from 'micromatch';
|
||||||
|
import { PrismaClient } from '@sourcebot/db';
|
||||||
|
|
||||||
const logger = createLogger('Gitea');
|
const logger = createLogger('Gitea');
|
||||||
|
|
||||||
export const getGiteaReposFromConfig = async (config: GiteaConfig, orgId: number, ctx: AppContext) => {
|
export const getGiteaReposFromConfig = async (config: GiteaConnectionConfig, orgId: number, db: PrismaClient) => {
|
||||||
// TODO: pass in DB here to fetch secret properly
|
// TODO: pass in DB here to fetch secret properly
|
||||||
const token = config.token ? await getTokenFromConfig(config.token, orgId) : undefined;
|
const token = config.token ? await getTokenFromConfig(config.token, orgId, db) : undefined;
|
||||||
|
|
||||||
const api = giteaApi(config.url ?? 'https://gitea.com', {
|
const api = giteaApi(config.url ?? 'https://gitea.com', {
|
||||||
token,
|
token,
|
||||||
|
|
@ -35,62 +34,22 @@ export const getGiteaReposFromConfig = async (config: GiteaConfig, orgId: number
|
||||||
allRepos = allRepos.concat(_repos);
|
allRepos = allRepos.concat(_repos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let repos: GitRepository[] = allRepos
|
allRepos = allRepos.filter(repo => repo.full_name !== undefined);
|
||||||
.map((repo) => {
|
allRepos = allRepos.filter(repo => {
|
||||||
const hostname = config.url ? new URL(config.url).hostname : 'gitea.com';
|
if (repo.full_name === undefined) {
|
||||||
const repoId = `${hostname}/${repo.full_name!}`;
|
logger.warn(`Repository with undefined full_name found: orgId=${orgId}, repoId=${repo.id}`);
|
||||||
const repoPath = path.resolve(path.join(ctx.reposPath, `${repoId}.git`));
|
return false;
|
||||||
|
|
||||||
const cloneUrl = new URL(repo.clone_url!);
|
|
||||||
if (token) {
|
|
||||||
cloneUrl.username = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
vcs: 'git',
|
|
||||||
codeHost: 'gitea',
|
|
||||||
name: repo.full_name!,
|
|
||||||
id: repoId,
|
|
||||||
cloneUrl: cloneUrl.toString(),
|
|
||||||
path: repoPath,
|
|
||||||
isStale: false,
|
|
||||||
isFork: repo.fork!,
|
|
||||||
isArchived: !!repo.archived,
|
|
||||||
gitConfigMetadata: {
|
|
||||||
'zoekt.web-url-type': 'gitea',
|
|
||||||
'zoekt.web-url': repo.html_url!,
|
|
||||||
'zoekt.name': repoId,
|
|
||||||
'zoekt.archived': marshalBool(repo.archived),
|
|
||||||
'zoekt.fork': marshalBool(repo.fork!),
|
|
||||||
'zoekt.public': marshalBool(repo.internal === false && repo.private === false),
|
|
||||||
},
|
|
||||||
branches: [],
|
|
||||||
tags: []
|
|
||||||
} satisfies GitRepository;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (config.exclude) {
|
|
||||||
if (!!config.exclude.forks) {
|
|
||||||
repos = excludeForkedRepos(repos, logger);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
if (!!config.exclude.archived) {
|
|
||||||
repos = excludeArchivedRepos(repos, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.exclude.repos) {
|
|
||||||
repos = excludeReposByName(repos, config.exclude.repos, logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug(`Found ${repos.length} total repositories.`);
|
|
||||||
|
|
||||||
if (config.revisions) {
|
if (config.revisions) {
|
||||||
if (config.revisions.branches) {
|
if (config.revisions.branches) {
|
||||||
const branchGlobs = config.revisions.branches;
|
const branchGlobs = config.revisions.branches;
|
||||||
repos = await Promise.all(
|
allRepos = await Promise.all(
|
||||||
repos.map(async (repo) => {
|
allRepos.map(async (repo) => {
|
||||||
const [owner, name] = repo.name.split('/');
|
const [owner, name] = repo.full_name!.split('/');
|
||||||
let branches = (await getBranchesForRepo(owner, name, api)).map(branch => branch.name!);
|
let branches = (await getBranchesForRepo(owner, name, api)).map(branch => branch.name!);
|
||||||
branches = micromatch.match(branches, branchGlobs);
|
branches = micromatch.match(branches, branchGlobs);
|
||||||
|
|
||||||
|
|
@ -104,14 +63,14 @@ export const getGiteaReposFromConfig = async (config: GiteaConfig, orgId: number
|
||||||
|
|
||||||
if (config.revisions.tags) {
|
if (config.revisions.tags) {
|
||||||
const tagGlobs = config.revisions.tags;
|
const tagGlobs = config.revisions.tags;
|
||||||
repos = await Promise.all(
|
allRepos = await Promise.all(
|
||||||
repos.map(async (repo) => {
|
allRepos.map(async (allRepos) => {
|
||||||
const [owner, name] = repo.name.split('/');
|
const [owner, name] = allRepos.name!.split('/');
|
||||||
let tags = (await getTagsForRepo(owner, name, api)).map(tag => tag.name!);
|
let tags = (await getTagsForRepo(owner, name, api)).map(tag => tag.name!);
|
||||||
tags = micromatch.match(tags, tagGlobs);
|
tags = micromatch.match(tags, tagGlobs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...repo,
|
...allRepos,
|
||||||
tags,
|
tags,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
@ -119,9 +78,62 @@ export const getGiteaReposFromConfig = async (config: GiteaConfig, orgId: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let repos = allRepos
|
||||||
|
.filter((repo) => {
|
||||||
|
const isExcluded = shouldExcludeRepo({
|
||||||
|
repo,
|
||||||
|
exclude: config.exclude,
|
||||||
|
});
|
||||||
|
|
||||||
|
return !isExcluded;
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.debug(`Found ${repos.length} total repositories.`);
|
||||||
return repos;
|
return repos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shouldExcludeRepo = ({
|
||||||
|
repo,
|
||||||
|
exclude
|
||||||
|
} : {
|
||||||
|
repo: GiteaRepository,
|
||||||
|
exclude?: {
|
||||||
|
forks?: boolean,
|
||||||
|
archived?: boolean,
|
||||||
|
repos?: string[],
|
||||||
|
}
|
||||||
|
}) => {
|
||||||
|
let reason = '';
|
||||||
|
const repoName = repo.full_name!;
|
||||||
|
|
||||||
|
const shouldExclude = (() => {
|
||||||
|
if (!!exclude?.forks && repo.fork) {
|
||||||
|
reason = `\`exclude.forks\` is true`;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!exclude?.archived && !!repo.archived) {
|
||||||
|
reason = `\`exclude.archived\` is true`;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exclude?.repos) {
|
||||||
|
if (micromatch.isMatch(repoName, exclude.repos)) {
|
||||||
|
reason = `\`exclude.repos\` contains ${repoName}`;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (shouldExclude) {
|
||||||
|
logger.debug(`Excluding repo ${repoName}. Reason: ${reason}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldExclude;
|
||||||
|
}
|
||||||
|
|
||||||
const getTagsForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
const getTagsForRepo = async <T>(owner: string, repo: string, api: Api<T>) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
logger.debug(`Fetching tags for repo ${owner}/${repo}...`);
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import { Gitlab, ProjectSchema } from "@gitbeaker/rest";
|
import { Gitlab, ProjectSchema } from "@gitbeaker/rest";
|
||||||
import micromatch from "micromatch";
|
import micromatch from "micromatch";
|
||||||
import { createLogger } from "./logger.js";
|
import { createLogger } from "./logger.js";
|
||||||
import { GitLabConfig } from "@sourcebot/schemas/v2/index.type"
|
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type"
|
||||||
import { AppContext } from "./types.js";
|
|
||||||
import { getTokenFromConfig, measure } from "./utils.js";
|
import { getTokenFromConfig, measure } from "./utils.js";
|
||||||
|
import { PrismaClient } from "@sourcebot/db";
|
||||||
|
|
||||||
const logger = createLogger("GitLab");
|
const logger = createLogger("GitLab");
|
||||||
export const GITLAB_CLOUD_HOSTNAME = "gitlab.com";
|
export const GITLAB_CLOUD_HOSTNAME = "gitlab.com";
|
||||||
|
|
||||||
export const getGitLabReposFromConfig = async (config: GitLabConfig, orgId: number, ctx: AppContext) => {
|
export const getGitLabReposFromConfig = async (config: GitlabConnectionConfig, orgId: number, db: PrismaClient) => {
|
||||||
// TODO: pass in DB here to fetch secret properly
|
const token = config.token ? await getTokenFromConfig(config.token, orgId, db) : undefined;
|
||||||
const token = config.token ? await getTokenFromConfig(config.token, orgId) : undefined;
|
|
||||||
const api = new Gitlab({
|
const api = new Gitlab({
|
||||||
...(config.token ? {
|
...(config.token ? {
|
||||||
token,
|
token,
|
||||||
|
|
@ -37,7 +36,7 @@ export const getGitLabReposFromConfig = async (config: GitLabConfig, orgId: numb
|
||||||
logger.error(`Failed to fetch all projects visible in ${config.url}.`, e);
|
logger.error(`Failed to fetch all projects visible in ${config.url}.`, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`Ignoring option all:true in ${ctx.configPath} : host is ${GITLAB_CLOUD_HOSTNAME}`);
|
logger.warn(`Ignoring option all:true in config : host is ${GITLAB_CLOUD_HOSTNAME}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,9 +118,9 @@ export const shouldExcludeProject = ({
|
||||||
}: {
|
}: {
|
||||||
project: ProjectSchema,
|
project: ProjectSchema,
|
||||||
include?: {
|
include?: {
|
||||||
topics?: GitLabConfig['topics'],
|
topics?: GitlabConnectionConfig['topics'],
|
||||||
},
|
},
|
||||||
exclude?: GitLabConfig['exclude'],
|
exclude?: GitlabConnectionConfig['exclude'],
|
||||||
}) => {
|
}) => {
|
||||||
const projectName = project.path_with_namespace;
|
const projectName = project.path_with_namespace;
|
||||||
let reason = '';
|
let reason = '';
|
||||||
|
|
|
||||||
208
packages/backend/src/repoCompileUtils.ts
Normal file
208
packages/backend/src/repoCompileUtils.ts
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
import { GithubConnectionConfig } from '@sourcebot/schemas/v3/github.type';
|
||||||
|
import { getGitHubReposFromConfig } from "./github.js";
|
||||||
|
import { getGitLabReposFromConfig } from "./gitlab.js";
|
||||||
|
import { getGiteaReposFromConfig } from "./gitea.js";
|
||||||
|
import { getGerritReposFromConfig } from "./gerrit.js";
|
||||||
|
import { Prisma, PrismaClient } from '@sourcebot/db';
|
||||||
|
import { WithRequired } from "./types.js"
|
||||||
|
import { marshalBool } from "./utils.js";
|
||||||
|
import { GerritConnectionConfig, GiteaConnectionConfig, GitlabConnectionConfig } from '@sourcebot/schemas/v3/connection.type';
|
||||||
|
|
||||||
|
export type RepoData = WithRequired<Prisma.RepoCreateInput, 'connections'>;
|
||||||
|
|
||||||
|
export const compileGithubConfig = async (
|
||||||
|
config: GithubConnectionConfig,
|
||||||
|
connectionId: number,
|
||||||
|
orgId: number,
|
||||||
|
db: PrismaClient,
|
||||||
|
abortController: AbortController): Promise<RepoData[]> => {
|
||||||
|
const gitHubRepos = await getGitHubReposFromConfig(config, orgId, db, abortController.signal);
|
||||||
|
const hostUrl = config.url ?? 'https://github.com';
|
||||||
|
const hostname = config.url ? new URL(config.url).hostname : 'github.com';
|
||||||
|
|
||||||
|
return gitHubRepos.map((repo) => {
|
||||||
|
const repoName = `${hostname}/${repo.full_name}`;
|
||||||
|
const cloneUrl = new URL(repo.clone_url!);
|
||||||
|
|
||||||
|
const record: RepoData = {
|
||||||
|
external_id: repo.id.toString(),
|
||||||
|
external_codeHostType: 'github',
|
||||||
|
external_codeHostUrl: hostUrl,
|
||||||
|
cloneUrl: cloneUrl.toString(),
|
||||||
|
name: repoName,
|
||||||
|
isFork: repo.fork,
|
||||||
|
isArchived: !!repo.archived,
|
||||||
|
org: {
|
||||||
|
connect: {
|
||||||
|
id: orgId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
connections: {
|
||||||
|
create: {
|
||||||
|
connectionId: connectionId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
'zoekt.web-url-type': 'github',
|
||||||
|
'zoekt.web-url': repo.html_url,
|
||||||
|
'zoekt.name': repoName,
|
||||||
|
'zoekt.github-stars': (repo.stargazers_count ?? 0).toString(),
|
||||||
|
'zoekt.github-watchers': (repo.watchers_count ?? 0).toString(),
|
||||||
|
'zoekt.github-subscribers': (repo.subscribers_count ?? 0).toString(),
|
||||||
|
'zoekt.github-forks': (repo.forks_count ?? 0).toString(),
|
||||||
|
'zoekt.archived': marshalBool(repo.archived),
|
||||||
|
'zoekt.fork': marshalBool(repo.fork),
|
||||||
|
'zoekt.public': marshalBool(repo.private === false)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return record;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const compileGitlabConfig = async (
|
||||||
|
config: GitlabConnectionConfig,
|
||||||
|
connectionId: number,
|
||||||
|
orgId: number,
|
||||||
|
db: PrismaClient) => {
|
||||||
|
|
||||||
|
const gitlabRepos = await getGitLabReposFromConfig(config, orgId, db);
|
||||||
|
const hostUrl = config.url ?? 'https://gitlab.com';
|
||||||
|
|
||||||
|
return gitlabRepos.map((project) => {
|
||||||
|
const projectUrl = `${hostUrl}/${project.path_with_namespace}`;
|
||||||
|
const cloneUrl = new URL(project.http_url_to_repo);
|
||||||
|
const isFork = project.forked_from_project !== undefined;
|
||||||
|
|
||||||
|
const record: RepoData = {
|
||||||
|
external_id: project.id.toString(),
|
||||||
|
external_codeHostType: 'gitlab',
|
||||||
|
external_codeHostUrl: hostUrl,
|
||||||
|
cloneUrl: cloneUrl.toString(),
|
||||||
|
name: project.path_with_namespace,
|
||||||
|
isFork: isFork,
|
||||||
|
isArchived: !!project.archived,
|
||||||
|
org: {
|
||||||
|
connect: {
|
||||||
|
id: orgId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
connections: {
|
||||||
|
create: {
|
||||||
|
connectionId: connectionId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
'zoekt.web-url-type': 'gitlab',
|
||||||
|
'zoekt.web-url': projectUrl,
|
||||||
|
'zoekt.name': project.path_with_namespace,
|
||||||
|
'zoekt.gitlab-stars': (project.stargazers_count ?? 0).toString(),
|
||||||
|
'zoekt.gitlab-forks': (project.forks_count ?? 0).toString(),
|
||||||
|
'zoekt.archived': marshalBool(project.archived),
|
||||||
|
'zoekt.fork': marshalBool(isFork),
|
||||||
|
'zoekt.public': marshalBool(project.private === false)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return record;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const compileGiteaConfig = async (
|
||||||
|
config: GiteaConnectionConfig,
|
||||||
|
connectionId: number,
|
||||||
|
orgId: number,
|
||||||
|
db: PrismaClient) => {
|
||||||
|
|
||||||
|
const giteaRepos = await getGiteaReposFromConfig(config, orgId, db);
|
||||||
|
const hostUrl = config.url ?? 'https://gitea.com';
|
||||||
|
|
||||||
|
return giteaRepos.map((repo) => {
|
||||||
|
const repoUrl = `${hostUrl}/${repo.full_name}`;
|
||||||
|
const cloneUrl = new URL(repo.clone_url!);
|
||||||
|
|
||||||
|
const record: RepoData = {
|
||||||
|
external_id: repo.id!.toString(),
|
||||||
|
external_codeHostType: 'gitea',
|
||||||
|
external_codeHostUrl: hostUrl,
|
||||||
|
cloneUrl: cloneUrl.toString(),
|
||||||
|
name: repo.full_name!,
|
||||||
|
isFork: repo.fork!,
|
||||||
|
isArchived: !!repo.archived,
|
||||||
|
org: {
|
||||||
|
connect: {
|
||||||
|
id: orgId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
connections: {
|
||||||
|
create: {
|
||||||
|
connectionId: connectionId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
'zoekt.web-url-type': 'gitea',
|
||||||
|
'zoekt.web-url': repo.html_url!,
|
||||||
|
'zoekt.name': repo.full_name!,
|
||||||
|
'zoekt.archived': marshalBool(repo.archived),
|
||||||
|
'zoekt.fork': marshalBool(repo.fork!),
|
||||||
|
'zoekt.public': marshalBool(repo.internal === false && repo.private === false),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return record;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const compileGerritConfig = async (
|
||||||
|
config: GerritConnectionConfig,
|
||||||
|
connectionId: number,
|
||||||
|
orgId: number) => {
|
||||||
|
|
||||||
|
const gerritRepos = await getGerritReposFromConfig(config);
|
||||||
|
const hostUrl = config.url ?? 'https://gerritcodereview.com';
|
||||||
|
const hostname = new URL(hostUrl).hostname;
|
||||||
|
|
||||||
|
return gerritRepos.map((project) => {
|
||||||
|
const repoId = `${hostname}/${project.name}`;
|
||||||
|
const cloneUrl = new URL(`${config.url}/${encodeURIComponent(project.name)}`);
|
||||||
|
|
||||||
|
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 record: RepoData = {
|
||||||
|
external_id: project.id.toString(),
|
||||||
|
external_codeHostType: 'gerrit',
|
||||||
|
external_codeHostUrl: hostUrl,
|
||||||
|
cloneUrl: cloneUrl.toString(),
|
||||||
|
name: project.name,
|
||||||
|
isFork: false,
|
||||||
|
isArchived: false,
|
||||||
|
org: {
|
||||||
|
connect: {
|
||||||
|
id: orgId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
connections: {
|
||||||
|
create: {
|
||||||
|
connectionId: connectionId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
'zoekt.web-url-type': 'gitiles',
|
||||||
|
'zoekt.web-url': webUrl,
|
||||||
|
'zoekt.name': repoId,
|
||||||
|
'zoekt.archived': marshalBool(false),
|
||||||
|
'zoekt.fork': marshalBool(false),
|
||||||
|
'zoekt.public': marshalBool(true),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return record;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import { Job, Queue, Worker } from 'bullmq';
|
||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
import { createLogger } from "./logger.js";
|
import { createLogger } from "./logger.js";
|
||||||
import { Connection, PrismaClient, Repo, RepoToConnection, RepoIndexingStatus } from "@sourcebot/db";
|
import { Connection, PrismaClient, Repo, RepoToConnection, RepoIndexingStatus } from "@sourcebot/db";
|
||||||
import { ConnectionConfig } from '@sourcebot/schemas/v3/connection.type';
|
import { GithubConnectionConfig, GitlabConnectionConfig, GiteaConnectionConfig } from '@sourcebot/schemas/v3/connection.type';
|
||||||
import { AppContext, Settings } from "./types.js";
|
import { AppContext, Settings } from "./types.js";
|
||||||
import { captureEvent } from "./posthog.js";
|
import { captureEvent } from "./posthog.js";
|
||||||
import { getRepoPath, getTokenFromConfig, measure, getShardPrefix } from "./utils.js";
|
import { getRepoPath, getTokenFromConfig, measure, getShardPrefix } from "./utils.js";
|
||||||
|
|
@ -74,7 +74,7 @@ export class RepoManager implements IRepoManager {
|
||||||
const repos = await this.db.repo.findMany({
|
const repos = await this.db.repo.findMany({
|
||||||
where: {
|
where: {
|
||||||
repoIndexingStatus: {
|
repoIndexingStatus: {
|
||||||
notIn: [RepoIndexingStatus.IN_INDEX_QUEUE, RepoIndexingStatus.FAILED]
|
notIn: [RepoIndexingStatus.IN_INDEX_QUEUE, RepoIndexingStatus.INDEXING, RepoIndexingStatus.FAILED]
|
||||||
},
|
},
|
||||||
OR: [
|
OR: [
|
||||||
{ indexedAt: null },
|
{ indexedAt: null },
|
||||||
|
|
@ -147,10 +147,15 @@ export class RepoManager implements IRepoManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let token: string | undefined;
|
let token: string | undefined;
|
||||||
for (const repoConnection of repoConnections) {
|
for (const repoConnection of repoConnections) {
|
||||||
const connection = repoConnection.connection;
|
const connection = repoConnection.connection;
|
||||||
const config = connection.config as unknown as ConnectionConfig;
|
if (connection.connectionType !== 'github' && connection.connectionType !== 'gitlab' && connection.connectionType !== 'gitea') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = connection.config as unknown as GithubConnectionConfig | GitlabConnectionConfig | GiteaConnectionConfig;
|
||||||
if (config.token) {
|
if (config.token) {
|
||||||
token = await getTokenFromConfig(config.token, connection.orgId, db);
|
token = await getTokenFromConfig(config.token, connection.orgId, db);
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ const schema = {
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "GitLabConnectionConfig",
|
"title": "GitlabConnectionConfig",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"const": "gitlab",
|
"const": "gitlab",
|
||||||
|
|
@ -352,6 +352,233 @@ const schema = {
|
||||||
"type"
|
"type"
|
||||||
],
|
],
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GiteaConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gitea",
|
||||||
|
"description": "Gitea Configuration"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"$ref": "#/oneOf/0/properties/token",
|
||||||
|
"description": "A Personal Access Token (PAT).",
|
||||||
|
"examples": [
|
||||||
|
"secret-token",
|
||||||
|
{
|
||||||
|
"env": "ENV_VAR_CONTAINING_TOKEN"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"default": "https://gitea.com",
|
||||||
|
"description": "The URL of the Gitea host. Defaults to https://gitea.com",
|
||||||
|
"examples": [
|
||||||
|
"https://gitea.com",
|
||||||
|
"https://gitea.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"orgs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"my-org-name"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of organizations to sync with. All repositories in the organization visible to the provided `token` (if any) will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:organization scope."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[\\w.-]+\\/[\\w.-]+$"
|
||||||
|
},
|
||||||
|
"description": "List of individual repositories to sync with. Expected to be formatted as '{orgName}/{repoName}' or '{userName}/{repoName}'."
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"username-1",
|
||||||
|
"username-2"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of users to sync with. All repositories that the user owns will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:user scope."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"forks": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude forked repositories from syncing."
|
||||||
|
},
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude archived repositories from syncing."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": [],
|
||||||
|
"description": "List of individual repositories to exclude from syncing. Glob patterns are supported."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"$ref": "#/oneOf/0/properties/revisions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gerrit",
|
||||||
|
"description": "Gerrit Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL of the Gerrit host.",
|
||||||
|
"examples": [
|
||||||
|
"https://gerrit.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "List of specific projects to sync. If not specified, all projects will be synced. Glob patterns are supported",
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of specific projects to exclude from syncing."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GitConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "git",
|
||||||
|
"description": "Git Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL to the git repository."
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"$ref": "#/oneOf/0/properties/revisions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "local",
|
||||||
|
"description": "Local Configuration"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path to the local directory to sync with. Relative paths are relative to the configuration file's directory.",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Enables a file watcher that will automatically re-sync when changes are made within `path` (recursively). Defaults to true."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paths": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"description": "List of paths relative to the provided `path` to exclude from the index. .git, .hg, and .svn are always exluded.",
|
||||||
|
"default": [],
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"node_modules",
|
||||||
|
"bin",
|
||||||
|
"dist",
|
||||||
|
"build",
|
||||||
|
"out"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
export type ConnectionConfig = GithubConnectionConfig | GitLabConnectionConfig;
|
export type ConnectionConfig =
|
||||||
|
| GithubConnectionConfig
|
||||||
|
| GitlabConnectionConfig
|
||||||
|
| GiteaConnectionConfig
|
||||||
|
| GerritConnectionConfig
|
||||||
|
| GitConnectionConfig
|
||||||
|
| GerritConnectionConfig1;
|
||||||
|
|
||||||
export interface GithubConnectionConfig {
|
export interface GithubConnectionConfig {
|
||||||
/**
|
/**
|
||||||
|
|
@ -92,7 +98,7 @@ export interface GitRevisions {
|
||||||
*/
|
*/
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
}
|
}
|
||||||
export interface GitLabConnectionConfig {
|
export interface GitlabConnectionConfig {
|
||||||
/**
|
/**
|
||||||
* GitLab Configuration
|
* GitLab Configuration
|
||||||
*/
|
*/
|
||||||
|
|
@ -160,3 +166,108 @@ export interface GitLabConnectionConfig {
|
||||||
};
|
};
|
||||||
revisions?: GitRevisions;
|
revisions?: GitRevisions;
|
||||||
}
|
}
|
||||||
|
export interface GiteaConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Gitea Configuration
|
||||||
|
*/
|
||||||
|
type: "gitea";
|
||||||
|
/**
|
||||||
|
* A Personal Access Token (PAT).
|
||||||
|
*/
|
||||||
|
token?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* The name of the environment variable that contains the token.
|
||||||
|
*/
|
||||||
|
env: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* The name of the secret that contains the token.
|
||||||
|
*/
|
||||||
|
secret: string;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The URL of the Gitea host. Defaults to https://gitea.com
|
||||||
|
*/
|
||||||
|
url?: string;
|
||||||
|
/**
|
||||||
|
* List of organizations to sync with. All repositories in the organization visible to the provided `token` (if any) will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:organization scope.
|
||||||
|
*/
|
||||||
|
orgs?: string[];
|
||||||
|
/**
|
||||||
|
* List of individual repositories to sync with. Expected to be formatted as '{orgName}/{repoName}' or '{userName}/{repoName}'.
|
||||||
|
*/
|
||||||
|
repos?: string[];
|
||||||
|
/**
|
||||||
|
* List of users to sync with. All repositories that the user owns will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:user scope.
|
||||||
|
*/
|
||||||
|
users?: string[];
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* Exclude forked repositories from syncing.
|
||||||
|
*/
|
||||||
|
forks?: boolean;
|
||||||
|
/**
|
||||||
|
* Exclude archived repositories from syncing.
|
||||||
|
*/
|
||||||
|
archived?: boolean;
|
||||||
|
/**
|
||||||
|
* List of individual repositories to exclude from syncing. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
repos?: string[];
|
||||||
|
};
|
||||||
|
revisions?: GitRevisions;
|
||||||
|
}
|
||||||
|
export interface GerritConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Gerrit Configuration
|
||||||
|
*/
|
||||||
|
type: "gerrit";
|
||||||
|
/**
|
||||||
|
* The URL of the Gerrit host.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
/**
|
||||||
|
* List of specific projects to sync. If not specified, all projects will be synced. Glob patterns are supported
|
||||||
|
*/
|
||||||
|
projects?: string[];
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* List of specific projects to exclude from syncing.
|
||||||
|
*/
|
||||||
|
projects?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface GitConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Git Configuration
|
||||||
|
*/
|
||||||
|
type: "git";
|
||||||
|
/**
|
||||||
|
* The URL to the git repository.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
revisions?: GitRevisions;
|
||||||
|
}
|
||||||
|
export interface GerritConnectionConfig1 {
|
||||||
|
/**
|
||||||
|
* Local Configuration
|
||||||
|
*/
|
||||||
|
type: "local";
|
||||||
|
/**
|
||||||
|
* Path to the local directory to sync with. Relative paths are relative to the configuration file's directory.
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/**
|
||||||
|
* Enables a file watcher that will automatically re-sync when changes are made within `path` (recursively). Defaults to true.
|
||||||
|
*/
|
||||||
|
watch?: boolean;
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* List of paths relative to the provided `path` to exclude from the index. .git, .hg, and .svn are always exluded.
|
||||||
|
*/
|
||||||
|
paths?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
59
packages/schemas/src/v3/gerrit.schema.ts
Normal file
59
packages/schemas/src/v3/gerrit.schema.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
const schema = {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gerrit",
|
||||||
|
"description": "Gerrit Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL of the Gerrit host.",
|
||||||
|
"examples": [
|
||||||
|
"https://gerrit.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "List of specific projects to sync. If not specified, all projects will be synced. Glob patterns are supported",
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of specific projects to exclude from syncing."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
} as const;
|
||||||
|
export { schema as gerritSchema };
|
||||||
22
packages/schemas/src/v3/gerrit.type.ts
Normal file
22
packages/schemas/src/v3/gerrit.type.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
|
export interface GerritConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Gerrit Configuration
|
||||||
|
*/
|
||||||
|
type: "gerrit";
|
||||||
|
/**
|
||||||
|
* The URL of the Gerrit host.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
/**
|
||||||
|
* List of specific projects to sync. If not specified, all projects will be synced. Glob patterns are supported
|
||||||
|
*/
|
||||||
|
projects?: string[];
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* List of specific projects to exclude from syncing.
|
||||||
|
*/
|
||||||
|
projects?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
64
packages/schemas/src/v3/git.schema.ts
Normal file
64
packages/schemas/src/v3/git.schema.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
const schema = {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GitConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "git",
|
||||||
|
"description": "Git Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL to the git repository."
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "The revisions (branches, tags) that should be included when indexing. The default branch (HEAD) is always indexed.",
|
||||||
|
"properties": {
|
||||||
|
"branches": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of branches to include when indexing. For a given repo, only the branches that exist on the repo's remote *and* match at least one of the provided `branches` will be indexed. The default branch (HEAD) is always indexed. Glob patterns are supported.",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"main",
|
||||||
|
"release/*"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"default": []
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of tags to include when indexing. For a given repo, only the tags that exist on the repo's remote *and* match at least one of the provided `tags` will be indexed. Glob patterns are supported.",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"latest",
|
||||||
|
"v2.*.*"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"default": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
} as const;
|
||||||
|
export { schema as gitSchema };
|
||||||
26
packages/schemas/src/v3/git.type.ts
Normal file
26
packages/schemas/src/v3/git.type.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
|
export interface GitConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Git Configuration
|
||||||
|
*/
|
||||||
|
type: "git";
|
||||||
|
/**
|
||||||
|
* The URL to the git repository.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
revisions?: GitRevisions;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The revisions (branches, tags) that should be included when indexing. The default branch (HEAD) is always indexed.
|
||||||
|
*/
|
||||||
|
export interface GitRevisions {
|
||||||
|
/**
|
||||||
|
* List of branches to include when indexing. For a given repo, only the branches that exist on the repo's remote *and* match at least one of the provided `branches` will be indexed. The default branch (HEAD) is always indexed. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
branches?: string[];
|
||||||
|
/**
|
||||||
|
* List of tags to include when indexing. For a given repo, only the tags that exist on the repo's remote *and* match at least one of the provided `tags` will be indexed. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
166
packages/schemas/src/v3/gitea.schema.ts
Normal file
166
packages/schemas/src/v3/gitea.schema.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
const schema = {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GiteaConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gitea",
|
||||||
|
"description": "Gitea Configuration"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"description": "A Personal Access Token (PAT).",
|
||||||
|
"examples": [
|
||||||
|
"secret-token",
|
||||||
|
{
|
||||||
|
"env": "ENV_VAR_CONTAINING_TOKEN"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"env": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the environment variable that contains the token."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"env"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"secret": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the secret that contains the token."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"secret"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"default": "https://gitea.com",
|
||||||
|
"description": "The URL of the Gitea host. Defaults to https://gitea.com",
|
||||||
|
"examples": [
|
||||||
|
"https://gitea.com",
|
||||||
|
"https://gitea.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"orgs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"my-org-name"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of organizations to sync with. All repositories in the organization visible to the provided `token` (if any) will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:organization scope."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[\\w.-]+\\/[\\w.-]+$"
|
||||||
|
},
|
||||||
|
"description": "List of individual repositories to sync with. Expected to be formatted as '{orgName}/{repoName}' or '{userName}/{repoName}'."
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"username-1",
|
||||||
|
"username-2"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of users to sync with. All repositories that the user owns will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:user scope."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"forks": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude forked repositories from syncing."
|
||||||
|
},
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude archived repositories from syncing."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": [],
|
||||||
|
"description": "List of individual repositories to exclude from syncing. Glob patterns are supported."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "The revisions (branches, tags) that should be included when indexing. The default branch (HEAD) is always indexed.",
|
||||||
|
"properties": {
|
||||||
|
"branches": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of branches to include when indexing. For a given repo, only the branches that exist on the repo's remote *and* match at least one of the provided `branches` will be indexed. The default branch (HEAD) is always indexed. Glob patterns are supported.",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"main",
|
||||||
|
"release/*"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"default": []
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of tags to include when indexing. For a given repo, only the tags that exist on the repo's remote *and* match at least one of the provided `tags` will be indexed. Glob patterns are supported.",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"latest",
|
||||||
|
"v2.*.*"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"default": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
} as const;
|
||||||
|
export { schema as giteaSchema };
|
||||||
69
packages/schemas/src/v3/gitea.type.ts
Normal file
69
packages/schemas/src/v3/gitea.type.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
|
export interface GiteaConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Gitea Configuration
|
||||||
|
*/
|
||||||
|
type: "gitea";
|
||||||
|
/**
|
||||||
|
* A Personal Access Token (PAT).
|
||||||
|
*/
|
||||||
|
token?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* The name of the environment variable that contains the token.
|
||||||
|
*/
|
||||||
|
env: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* The name of the secret that contains the token.
|
||||||
|
*/
|
||||||
|
secret: string;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The URL of the Gitea host. Defaults to https://gitea.com
|
||||||
|
*/
|
||||||
|
url?: string;
|
||||||
|
/**
|
||||||
|
* List of organizations to sync with. All repositories in the organization visible to the provided `token` (if any) will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:organization scope.
|
||||||
|
*/
|
||||||
|
orgs?: string[];
|
||||||
|
/**
|
||||||
|
* List of individual repositories to sync with. Expected to be formatted as '{orgName}/{repoName}' or '{userName}/{repoName}'.
|
||||||
|
*/
|
||||||
|
repos?: string[];
|
||||||
|
/**
|
||||||
|
* List of users to sync with. All repositories that the user owns will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:user scope.
|
||||||
|
*/
|
||||||
|
users?: string[];
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* Exclude forked repositories from syncing.
|
||||||
|
*/
|
||||||
|
forks?: boolean;
|
||||||
|
/**
|
||||||
|
* Exclude archived repositories from syncing.
|
||||||
|
*/
|
||||||
|
archived?: boolean;
|
||||||
|
/**
|
||||||
|
* List of individual repositories to exclude from syncing. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
repos?: string[];
|
||||||
|
};
|
||||||
|
revisions?: GitRevisions;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The revisions (branches, tags) that should be included when indexing. The default branch (HEAD) is always indexed.
|
||||||
|
*/
|
||||||
|
export interface GitRevisions {
|
||||||
|
/**
|
||||||
|
* List of branches to include when indexing. For a given repo, only the branches that exist on the repo's remote *and* match at least one of the provided `branches` will be indexed. The default branch (HEAD) is always indexed. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
branches?: string[];
|
||||||
|
/**
|
||||||
|
* List of tags to include when indexing. For a given repo, only the tags that exist on the repo's remote *and* match at least one of the provided `tags` will be indexed. Glob patterns are supported.
|
||||||
|
*/
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
const schema = {
|
const schema = {
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "GitLabConnectionConfig",
|
"title": "GitlabConnectionConfig",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"const": "gitlab",
|
"const": "gitlab",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
export interface GitLabConnectionConfig {
|
export interface GitlabConnectionConfig {
|
||||||
/**
|
/**
|
||||||
* GitLab Configuration
|
* GitLab Configuration
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
52
packages/schemas/src/v3/local.schema.ts
Normal file
52
packages/schemas/src/v3/local.schema.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
const schema = {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "local",
|
||||||
|
"description": "Local Configuration"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path to the local directory to sync with. Relative paths are relative to the configuration file's directory.",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Enables a file watcher that will automatically re-sync when changes are made within `path` (recursively). Defaults to true."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paths": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"description": "List of paths relative to the provided `path` to exclude from the index. .git, .hg, and .svn are always exluded.",
|
||||||
|
"default": [],
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"node_modules",
|
||||||
|
"bin",
|
||||||
|
"dist",
|
||||||
|
"build",
|
||||||
|
"out"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
} as const;
|
||||||
|
export { schema as localSchema };
|
||||||
22
packages/schemas/src/v3/local.type.ts
Normal file
22
packages/schemas/src/v3/local.type.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY!
|
||||||
|
|
||||||
|
export interface GerritConnectionConfig {
|
||||||
|
/**
|
||||||
|
* Local Configuration
|
||||||
|
*/
|
||||||
|
type: "local";
|
||||||
|
/**
|
||||||
|
* Path to the local directory to sync with. Relative paths are relative to the configuration file's directory.
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/**
|
||||||
|
* Enables a file watcher that will automatically re-sync when changes are made within `path` (recursively). Defaults to true.
|
||||||
|
*/
|
||||||
|
watch?: boolean;
|
||||||
|
exclude?: {
|
||||||
|
/**
|
||||||
|
* List of paths relative to the provided `path` to exclude from the index. .git, .hg, and .svn are always exluded.
|
||||||
|
*/
|
||||||
|
paths?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,8 @@ import { ErrorCode } from "@/lib/errorCodes";
|
||||||
import { isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import { githubSchema } from "@sourcebot/schemas/v3/github.schema";
|
import { githubSchema } from "@sourcebot/schemas/v3/github.schema";
|
||||||
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
||||||
|
import { giteaSchema } from "@sourcebot/schemas/v3/gitea.schema";
|
||||||
|
import { gerritSchema } from "@sourcebot/schemas/v3/gerrit.schema";
|
||||||
import { ConnectionConfig } from "@sourcebot/schemas/v3/connection.type";
|
import { ConnectionConfig } from "@sourcebot/schemas/v3/connection.type";
|
||||||
import { encrypt } from "@sourcebot/crypto"
|
import { encrypt } from "@sourcebot/crypto"
|
||||||
import { getConnection } from "./data/connection";
|
import { getConnection } from "./data/connection";
|
||||||
|
|
@ -515,6 +517,10 @@ const parseConnectionConfig = (connectionType: string, config: string) => {
|
||||||
return githubSchema;
|
return githubSchema;
|
||||||
case "gitlab":
|
case "gitlab":
|
||||||
return gitlabSchema;
|
return gitlabSchema;
|
||||||
|
case 'gitea':
|
||||||
|
return giteaSchema;
|
||||||
|
case 'gerrit':
|
||||||
|
return gerritSchema;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,18 @@ import { z } from "zod";
|
||||||
import { ConfigEditor, QuickAction } from "../../components/configEditor";
|
import { ConfigEditor, QuickAction } from "../../components/configEditor";
|
||||||
import { createZodConnectionConfigValidator } from "../../utils";
|
import { createZodConnectionConfigValidator } from "../../utils";
|
||||||
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
||||||
import { githubQuickActions, gitlabQuickActions } from "../../quickActions";
|
import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/gitea.type";
|
||||||
|
import { GerritConnectionConfig } from "@sourcebot/schemas/v3/gerrit.type";
|
||||||
|
import { githubQuickActions, gitlabQuickActions, giteaQuickActions, gerritQuickActions } from "../../quickActions";
|
||||||
import { Schema } from "ajv";
|
import { Schema } from "ajv";
|
||||||
import { GitLabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
||||||
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
||||||
import { updateConnectionConfigAndScheduleSync } from "@/actions";
|
import { updateConnectionConfigAndScheduleSync } from "@/actions";
|
||||||
import { useToast } from "@/components/hooks/use-toast";
|
import { useToast } from "@/components/hooks/use-toast";
|
||||||
import { isServiceError } from "@/lib/utils";
|
import { isServiceError } from "@/lib/utils";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { giteaSchema } from "@sourcebot/schemas/v3/gitea.schema";
|
||||||
|
import { gerritSchema } from "@sourcebot/schemas/v3/gerrit.schema";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -40,13 +44,29 @@ export const ConfigSetting = (props: ConfigSettingProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'gitlab') {
|
if (type === 'gitlab') {
|
||||||
return <ConfigSettingInternal<GitLabConnectionConfig>
|
return <ConfigSettingInternal<GitlabConnectionConfig>
|
||||||
{...props}
|
{...props}
|
||||||
quickActions={gitlabQuickActions}
|
quickActions={gitlabQuickActions}
|
||||||
schema={gitlabSchema}
|
schema={gitlabSchema}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'gitea') {
|
||||||
|
return <ConfigSettingInternal<GiteaConnectionConfig>
|
||||||
|
{...props}
|
||||||
|
quickActions={giteaQuickActions}
|
||||||
|
schema={giteaSchema}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'gerrit') {
|
||||||
|
return <ConfigSettingInternal<GerritConnectionConfig>
|
||||||
|
{...props}
|
||||||
|
quickActions={gerritQuickActions}
|
||||||
|
schema={gerritSchema}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { ConfigEditor, QuickActionFn } from "../../../components/configEditor";
|
||||||
import { useDomain } from "@/hooks/useDomain";
|
import { useDomain } from "@/hooks/useDomain";
|
||||||
|
|
||||||
interface ConnectionCreationForm<T> {
|
interface ConnectionCreationForm<T> {
|
||||||
type: 'github' | 'gitlab';
|
type: 'github' | 'gitlab' | 'gitea' | 'gerrit';
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: string;
|
name: string;
|
||||||
config: string;
|
config: string;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { githubQuickActions, gitlabQuickActions } from "../../quickActions";
|
import { gerritQuickActions, giteaQuickActions, githubQuickActions, gitlabQuickActions } from "../../quickActions";
|
||||||
import ConnectionCreationForm from "./components/connectionCreationForm";
|
import ConnectionCreationForm from "./components/connectionCreationForm";
|
||||||
import { GitLabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
||||||
|
import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/gitea.type";
|
||||||
|
import { GerritConnectionConfig } from "@sourcebot/schemas/v3/gerrit.type";
|
||||||
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
import { gitlabSchema } from "@sourcebot/schemas/v3/gitlab.schema";
|
||||||
import { githubSchema } from "@sourcebot/schemas/v3/github.schema";
|
import { githubSchema } from "@sourcebot/schemas/v3/github.schema";
|
||||||
|
import { giteaSchema } from "@sourcebot/schemas/v3/gitea.schema";
|
||||||
|
import { gerritSchema } from "@sourcebot/schemas/v3/gerrit.schema";
|
||||||
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
|
@ -22,16 +26,24 @@ export default function NewConnectionPage({
|
||||||
return <GitLabCreationForm />;
|
return <GitLabCreationForm />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'gitea') {
|
||||||
|
return <GiteaCreationForm />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'gerrit') {
|
||||||
|
return <GerritCreationForm />;
|
||||||
|
}
|
||||||
|
|
||||||
router.push('/connections');
|
router.push('/connections');
|
||||||
}
|
}
|
||||||
|
|
||||||
const GitLabCreationForm = () => {
|
const GitLabCreationForm = () => {
|
||||||
const defaultConfig: GitLabConnectionConfig = {
|
const defaultConfig: GitlabConnectionConfig = {
|
||||||
type: 'gitlab',
|
type: 'gitlab',
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConnectionCreationForm<GitLabConnectionConfig>
|
<ConnectionCreationForm<GitlabConnectionConfig>
|
||||||
type="gitlab"
|
type="gitlab"
|
||||||
title="Create a GitLab connection"
|
title="Create a GitLab connection"
|
||||||
defaultValues={{
|
defaultValues={{
|
||||||
|
|
@ -62,3 +74,42 @@ const GitHubCreationForm = () => {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GiteaCreationForm = () => {
|
||||||
|
const defaultConfig: GiteaConnectionConfig = {
|
||||||
|
type: 'gitea',
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConnectionCreationForm<GiteaConnectionConfig>
|
||||||
|
type="gitea"
|
||||||
|
title="Create a Gitea connection"
|
||||||
|
defaultValues={{
|
||||||
|
config: JSON.stringify(defaultConfig, null, 2),
|
||||||
|
name: 'my-gitea-connection',
|
||||||
|
}}
|
||||||
|
schema={giteaSchema}
|
||||||
|
quickActions={giteaQuickActions}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const GerritCreationForm = () => {
|
||||||
|
const defaultConfig: GerritConnectionConfig = {
|
||||||
|
type: 'gerrit',
|
||||||
|
url: "https://gerrit.example.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConnectionCreationForm<GerritConnectionConfig>
|
||||||
|
type="gerrit"
|
||||||
|
title="Create a Gerrit connection"
|
||||||
|
defaultValues={{
|
||||||
|
config: JSON.stringify(defaultConfig, null, 2),
|
||||||
|
name: 'my-gerrit-connection',
|
||||||
|
}}
|
||||||
|
schema={gerritSchema}
|
||||||
|
quickActions={gerritQuickActions}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type"
|
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type"
|
||||||
import { GitLabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type";
|
||||||
import { QuickAction } from "./components/configEditor";
|
import { QuickAction } from "./components/configEditor";
|
||||||
|
import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/connection.type";
|
||||||
|
import { GerritConnectionConfig } from "@sourcebot/schemas/v3/gerrit.type";
|
||||||
|
|
||||||
export const githubQuickActions: QuickAction<GithubConnectionConfig>[] = [
|
export const githubQuickActions: QuickAction<GithubConnectionConfig>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -41,9 +43,9 @@ export const githubQuickActions: QuickAction<GithubConnectionConfig>[] = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const gitlabQuickActions: QuickAction<GitLabConnectionConfig>[] = [
|
export const gitlabQuickActions: QuickAction<GitlabConnectionConfig>[] = [
|
||||||
{
|
{
|
||||||
fn: (previous: GitLabConnectionConfig) => ({
|
fn: (previous: GitlabConnectionConfig) => ({
|
||||||
...previous,
|
...previous,
|
||||||
groups: [
|
groups: [
|
||||||
...previous.groups ?? [],
|
...previous.groups ?? [],
|
||||||
|
|
@ -53,14 +55,14 @@ export const gitlabQuickActions: QuickAction<GitLabConnectionConfig>[] = [
|
||||||
name: "Add a group",
|
name: "Add a group",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fn: (previous: GitLabConnectionConfig) => ({
|
fn: (previous: GitlabConnectionConfig) => ({
|
||||||
...previous,
|
...previous,
|
||||||
url: previous.url ?? "",
|
url: previous.url ?? "",
|
||||||
}),
|
}),
|
||||||
name: "Set a custom url",
|
name: "Set a custom url",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fn: (previous: GitLabConnectionConfig) => ({
|
fn: (previous: GitlabConnectionConfig) => ({
|
||||||
...previous,
|
...previous,
|
||||||
token: previous.token ?? {
|
token: previous.token ?? {
|
||||||
secret: "",
|
secret: "",
|
||||||
|
|
@ -69,7 +71,7 @@ export const gitlabQuickActions: QuickAction<GitLabConnectionConfig>[] = [
|
||||||
name: "Add a secret",
|
name: "Add a secret",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fn: (previous: GitLabConnectionConfig) => ({
|
fn: (previous: GitlabConnectionConfig) => ({
|
||||||
...previous,
|
...previous,
|
||||||
projects: [
|
projects: [
|
||||||
...previous.projects ?? [],
|
...previous.projects ?? [],
|
||||||
|
|
@ -80,3 +82,68 @@ export const gitlabQuickActions: QuickAction<GitLabConnectionConfig>[] = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const giteaQuickActions: QuickAction<GiteaConnectionConfig>[] = [
|
||||||
|
{
|
||||||
|
fn: (previous: GiteaConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
orgs: [
|
||||||
|
...(previous.orgs ?? []),
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
name: "Add an organization",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (previous: GiteaConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
url: previous.url ?? "",
|
||||||
|
}),
|
||||||
|
name: "Set a custom url",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (previous: GiteaConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
repos: [
|
||||||
|
...(previous.repos ?? []),
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
name: "Add a repo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (previous: GiteaConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
token: previous.token ?? {
|
||||||
|
secret: "",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
name: "Add a secret",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const gerritQuickActions: QuickAction<GerritConnectionConfig>[] = [
|
||||||
|
{
|
||||||
|
fn: (previous: GerritConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
projects: [
|
||||||
|
...(previous.projects ?? []),
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
name: "Add a project",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (previous: GerritConnectionConfig) => ({
|
||||||
|
...previous,
|
||||||
|
exclude: {
|
||||||
|
...previous.exclude,
|
||||||
|
projects: [
|
||||||
|
...(previous.exclude?.projects ?? []),
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
name: "Exclude a project",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ export function OrgCreateForm({ setOrgCreateData }: OrgCreateFormProps) {
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Input placeholder="aperature-labs" {...field} className="w-1/2" />
|
<Input placeholder="aperature-labs" {...field} className="w-1/2" />
|
||||||
<span className="ml-2">.sourcebot.dev</span>
|
<span className="ml-2">.sourcebot.app</span>
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,18 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "./gitlab.json"
|
"$ref": "./gitlab.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "./gitea.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "./gerrit.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "./git.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "./local.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
57
schemas/v3/gerrit.json
Normal file
57
schemas/v3/gerrit.json
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gerrit",
|
||||||
|
"description": "Gerrit Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL of the Gerrit host.",
|
||||||
|
"examples": [
|
||||||
|
"https://gerrit.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "List of specific projects to sync. If not specified, all projects will be synced. Glob patterns are supported",
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"projects": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"project1/repo1",
|
||||||
|
"project2/**"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of specific projects to exclude from syncing."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
24
schemas/v3/git.json
Normal file
24
schemas/v3/git.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GitConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "git",
|
||||||
|
"description": "Git Configuration"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "The URL to the git repository."
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"$ref": "./shared.json#/definitions/GitRevisions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
96
schemas/v3/gitea.json
Normal file
96
schemas/v3/gitea.json
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GiteaConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "gitea",
|
||||||
|
"description": "Gitea Configuration"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"$ref": "./shared.json#/definitions/Token",
|
||||||
|
"description": "A Personal Access Token (PAT).",
|
||||||
|
"examples": [
|
||||||
|
"secret-token",
|
||||||
|
{
|
||||||
|
"env": "ENV_VAR_CONTAINING_TOKEN"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"default": "https://gitea.com",
|
||||||
|
"description": "The URL of the Gitea host. Defaults to https://gitea.com",
|
||||||
|
"examples": [
|
||||||
|
"https://gitea.com",
|
||||||
|
"https://gitea.example.com"
|
||||||
|
],
|
||||||
|
"pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$"
|
||||||
|
},
|
||||||
|
"orgs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"my-org-name"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of organizations to sync with. All repositories in the organization visible to the provided `token` (if any) will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:organization scope."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[\\w.-]+\\/[\\w.-]+$"
|
||||||
|
},
|
||||||
|
"description": "List of individual repositories to sync with. Expected to be formatted as '{orgName}/{repoName}' or '{userName}/{repoName}'."
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"username-1",
|
||||||
|
"username-2"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"description": "List of users to sync with. All repositories that the user owns will be synced, unless explicitly defined in the `exclude` property. If a `token` is provided, it must have the read:user scope."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"forks": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude forked repositories from syncing."
|
||||||
|
},
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Exclude archived repositories from syncing."
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": [],
|
||||||
|
"description": "List of individual repositories to exclude from syncing. Glob patterns are supported."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"revisions": {
|
||||||
|
"$ref": "./shared.json#/definitions/GitRevisions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "GitLabConnectionConfig",
|
"title": "GitlabConnectionConfig",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"const": "gitlab",
|
"const": "gitlab",
|
||||||
|
|
|
||||||
50
schemas/v3/local.json
Normal file
50
schemas/v3/local.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "GerritConnectionConfig",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "local",
|
||||||
|
"description": "Local Configuration"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path to the local directory to sync with. Relative paths are relative to the configuration file's directory.",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Enables a file watcher that will automatically re-sync when changes are made within `path` (recursively). Defaults to true."
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paths": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": ".+"
|
||||||
|
},
|
||||||
|
"description": "List of paths relative to the provided `path` to exclude from the index. .git, .hg, and .svn are always exluded.",
|
||||||
|
"default": [],
|
||||||
|
"examples": [
|
||||||
|
[
|
||||||
|
"node_modules",
|
||||||
|
"bin",
|
||||||
|
"dist",
|
||||||
|
"build",
|
||||||
|
"out"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue