@cyphbt/gitlab-mcp-server
Version:
GitLab MCP Server with tag and merge request functionality - supports both Token and SSH modes
194 lines • 6.26 kB
JavaScript
import { execSync } from 'child_process';
import { existsSync } from 'fs';
import { join } from 'path';
export class GitDetector {
/**
* 查找 Git 仓库的根目录
*/
static findGitRoot(startPath = process.cwd()) {
try {
// 使用 git rev-parse --show-toplevel 命令找到 Git 根目录
const gitRoot = execSync('git rev-parse --show-toplevel', {
cwd: startPath,
encoding: 'utf8',
}).trim();
return gitRoot;
}
catch (error) {
// 如果命令失败,说明不在 Git 仓库中
return null;
}
}
/**
* 自动切换到 Git 根目录
*/
static changeToGitRoot() {
const gitRoot = this.findGitRoot();
if (gitRoot) {
try {
process.chdir(gitRoot);
console.error(`📁 自动切换到 Git 根目录: ${gitRoot}`);
return gitRoot;
}
catch (error) {
console.error(`❌ 无法切换到 Git 根目录: ${gitRoot}`);
return null;
}
}
return null;
}
/**
* 检测当前目录的 Git 信息
*/
static detectGitInfo(projectPath = process.cwd()) {
try {
// 检查是否是 Git 仓库
const gitDir = join(projectPath, '.git');
if (!existsSync(gitDir)) {
return {
remoteUrl: '',
currentBranch: '',
projectPath,
isGitRepo: false,
};
}
// 获取远程仓库 URL
const remoteUrl = execSync('git remote get-url origin', {
cwd: projectPath,
encoding: 'utf8',
}).trim();
// 获取当前分支
const currentBranch = execSync('git branch --show-current', {
cwd: projectPath,
encoding: 'utf8',
}).trim();
return {
remoteUrl,
currentBranch,
projectPath,
isGitRepo: true,
};
}
catch (error) {
return {
remoteUrl: '',
currentBranch: '',
projectPath,
isGitRepo: false,
};
}
}
/**
* 从 Git 远程 URL 解析 GitLab 信息
*/
static parseGitLabInfo(gitInfo) {
if (!gitInfo.isGitRepo || !gitInfo.remoteUrl) {
return null;
}
const { remoteUrl } = gitInfo;
// 支持多种 GitLab URL 格式
let gitlabUrl = '';
let projectPath = '';
// HTTPS 格式: https://gitlab.com/group/project.git
if (remoteUrl.startsWith('https://')) {
const url = new URL(remoteUrl);
gitlabUrl = `${url.protocol}//${url.host}`;
projectPath = url.pathname.replace(/\.git$/, '').replace(/^\//, '');
}
// SSH 格式: git@gitlab.com:group/project.git
else if (remoteUrl.startsWith('git@')) {
const match = remoteUrl.match(/git@([^:]+):(.+)\.git/);
if (match) {
gitlabUrl = `https://${match[1]}`;
projectPath = match[2];
}
}
// 其他格式
else {
return null;
}
if (!gitlabUrl || !projectPath) {
return null;
}
return {
gitlabUrl,
projectPath,
currentBranch: gitInfo.currentBranch,
};
}
/**
* 获取项目 ID(需要调用 GitLab API)
*/
static async getProjectId(gitlabUrl, projectPath, token) {
try {
const { default: axios } = await import('axios');
const response = await axios.get(`${gitlabUrl}/api/v4/projects/${encodeURIComponent(projectPath)}`, {
headers: {
'Authorization': `Bearer ${token}`,
},
});
return response.data.id.toString();
}
catch (error) {
console.error('获取项目 ID 失败:', error);
return null;
}
}
/**
* 检测 GitLab 配置
*/
static async detectGitLabConfig(token, projectPath) {
const gitInfo = this.detectGitInfo(projectPath);
if (!gitInfo.isGitRepo) {
throw new Error('当前目录不是 Git 仓库');
}
const gitlabInfo = this.parseGitLabInfo(gitInfo);
if (!gitlabInfo) {
throw new Error('无法解析 GitLab 仓库信息');
}
const projectId = await this.getProjectId(gitlabInfo.gitlabUrl, gitlabInfo.projectPath, token);
if (!projectId) {
throw new Error('无法获取项目 ID,请检查 Token 权限');
}
return {
gitlabUrl: gitlabInfo.gitlabUrl,
projectId,
currentBranch: gitlabInfo.currentBranch,
};
}
/**
* 获取 Git 配置信息
*/
static getGitConfig(projectPath = process.cwd()) {
try {
const name = execSync('git config user.name', {
cwd: projectPath,
encoding: 'utf8',
}).trim();
const email = execSync('git config user.email', {
cwd: projectPath,
encoding: 'utf8',
}).trim();
return { user: { name, email } };
}
catch (error) {
return { user: { name: '', email: '' } };
}
}
/**
* 获取最近的提交信息
*/
static getRecentCommits(projectPath = process.cwd(), limit = 5) {
try {
const output = execSync(`git log --oneline --format="%H|%h|%s|%an|%ad" --date=short -${limit}`, { cwd: projectPath, encoding: 'utf8' });
return output.trim().split('\n').map(line => {
const [hash, shortHash, message, author, date] = line.split('|');
return { hash, shortHash, message, author, date };
});
}
catch (error) {
return [];
}
}
}
//# sourceMappingURL=git-detector.js.map