implement raw remote git repo support (#152)

* implement raw remote git repo support

* add changelog entry
This commit is contained in:
Michael Sukkarieh 2025-01-09 09:10:30 -08:00 committed by GitHub
parent 672832c993
commit d269a8cbe6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 124 additions and 3 deletions

View file

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added support for creating share links to snippets of code. ([#149](https://github.com/sourcebot-dev/sourcebot/pull/149)) - Added support for creating share links to snippets of code. ([#149](https://github.com/sourcebot-dev/sourcebot/pull/149))
- Added support for indexing raw remote git repository. ([#152](https://github.com/sourcebot-dev/sourcebot/pull/152))
## [2.6.3] - 2024-12-18 ## [2.6.3] - 2024-12-18

View file

@ -1,7 +1,9 @@
import { GitRepository } from './types.js'; import { GitRepository, AppContext } from './types.js';
import { simpleGit, SimpleGitProgressEvent } from 'simple-git'; import { simpleGit, SimpleGitProgressEvent } from 'simple-git';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { createLogger } from './logger.js'; import { createLogger } from './logger.js';
import { GitConfig } from './schemas/v2.js';
import path from 'path';
const logger = createLogger('git'); const logger = createLogger('git');
@ -49,3 +51,80 @@ export const fetchRepository = async (repo: GitRepository, onProgress?: (event:
] ]
); );
} }
const isValidGitRepo = async (url: string): Promise<boolean> => {
const git = simpleGit();
try {
await git.listRemote([url]);
return true;
} catch (error) {
logger.debug(`Error checking if ${url} is a valid git repo: ${error}`);
return false;
}
}
const stripProtocolAndGitSuffix = (url: string): string => {
return url.replace(/^[a-zA-Z]+:\/\//, '').replace(/\.git$/, '');
}
const getRepoNameFromUrl = (url: string): string => {
const strippedUrl = stripProtocolAndGitSuffix(url);
return strippedUrl.split('/').slice(-2).join('/');
}
export const getGitRepoFromConfig = async (config: GitConfig, ctx: AppContext) => {
const repoValid = await isValidGitRepo(config.url);
if (!repoValid) {
logger.error(`Git repo provided in config with url ${config.url} is not valid`);
return null;
}
const cloneUrl = config.url;
const repoId = stripProtocolAndGitSuffix(cloneUrl);
const repoName = getRepoNameFromUrl(config.url);
const repoPath = path.resolve(path.join(ctx.reposPath, `${repoId}.git`));
const repo: GitRepository = {
vcs: 'git',
id: repoId,
name: repoName,
path: repoPath,
isStale: false,
cloneUrl: cloneUrl,
branches: [],
tags: [],
}
if (config.revisions) {
if (config.revisions.branches) {
const branchGlobs = config.revisions.branches;
const git = simpleGit();
const branchList = await git.listRemote(['--heads', cloneUrl]);
const branches = branchList
.split('\n')
.map(line => line.split('\t')[1])
.filter(Boolean)
.map(branch => branch.replace('refs/heads/', ''));
repo.branches = branches.filter(branch =>
branchGlobs.some(glob => new RegExp(glob).test(branch))
);
}
if (config.revisions.tags) {
const tagGlobs = config.revisions.tags;
const git = simpleGit();
const tagList = await git.listRemote(['--tags', cloneUrl]);
const tags = tagList
.split('\n')
.map(line => line.split('\t')[1])
.filter(Boolean)
.map(tag => tag.replace('refs/tags/', ''));
repo.tags = tags.filter(tag =>
tagGlobs.some(glob => new RegExp(glob).test(tag))
);
}
}
return repo;
}

View file

@ -6,7 +6,7 @@ import { getGitLabReposFromConfig } from "./gitlab.js";
import { getGiteaReposFromConfig } from "./gitea.js"; import { getGiteaReposFromConfig } from "./gitea.js";
import { getGerritReposFromConfig } from "./gerrit.js"; import { getGerritReposFromConfig } from "./gerrit.js";
import { AppContext, LocalRepository, GitRepository, Repository, Settings } from "./types.js"; import { AppContext, LocalRepository, GitRepository, Repository, Settings } from "./types.js";
import { cloneRepository, fetchRepository } from "./git.js"; import { cloneRepository, fetchRepository, getGitRepoFromConfig } from "./git.js";
import { createLogger } from "./logger.js"; import { createLogger } from "./logger.js";
import { createRepository, Database, loadDB, updateRepository, updateSettings } from './db.js'; import { createRepository, Database, loadDB, updateRepository, updateSettings } from './db.js';
import { arraysEqualShallow, isRemotePath, measure } from "./utils.js"; import { arraysEqualShallow, isRemotePath, measure } from "./utils.js";
@ -245,6 +245,11 @@ const syncConfig = async (configPath: string, db: Database, signal: AbortSignal,
configRepos.push(repo); configRepos.push(repo);
break; break;
} }
case 'git': {
const gitRepo = await getGitRepoFromConfig(repoConfig, ctx);
gitRepo && configRepos.push(gitRepo);
break;
}
} }
} }

View file

@ -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 type Repos = GitHubConfig | GitLabConfig | GiteaConfig | GerritConfig | LocalConfig; export type Repos = GitHubConfig | GitLabConfig | GiteaConfig | GerritConfig | LocalConfig | GitConfig;
/** /**
* A Sourcebot configuration file outlines which repositories Sourcebot should sync and index. * A Sourcebot configuration file outlines which repositories Sourcebot should sync and index.
@ -268,3 +268,14 @@ export interface LocalConfig {
paths?: string[]; paths?: string[];
}; };
} }
export interface GitConfig {
/**
* Git Configuration
*/
type: "git";
/**
* The URL to the git repository.
*/
url: string;
revisions?: GitRevisions;
}

View file

@ -516,6 +516,28 @@
], ],
"additionalProperties": false "additionalProperties": false
}, },
"GitConfig": {
"type": "object",
"properties": {
"type": {
"const": "git",
"description": "Git Configuration"
},
"url": {
"type": "string",
"format": "url",
"description": "The URL to the git repository."
},
"revisions": {
"$ref": "#/definitions/GitRevisions"
}
},
"required": [
"type",
"url"
],
"additionalProperties": false
},
"Repos": { "Repos": {
"anyOf": [ "anyOf": [
{ {
@ -532,6 +554,9 @@
}, },
{ {
"$ref": "#/definitions/LocalConfig" "$ref": "#/definitions/LocalConfig"
},
{
"$ref": "#/definitions/GitConfig"
} }
] ]
}, },