/** * TASKMATE - Gitea Service * ========================= * Integration mit Gitea API */ const logger = require('../utils/logger'); const GITEA_URL = process.env.GITEA_URL || 'https://gitea-undso.aegis-sight.de'; const GITEA_TOKEN = process.env.GITEA_TOKEN; const GITEA_ORG = process.env.GITEA_ORG || 'AegisSight'; // Standard-Organisation für neue Repos /** * Basis-Fetch für Gitea API */ async function giteaFetch(endpoint, options = {}) { if (!GITEA_TOKEN) { throw new Error('Gitea-Token nicht konfiguriert'); } const url = `${GITEA_URL}/api/v1${endpoint}`; const response = await fetch(url, { ...options, headers: { 'Authorization': `token ${GITEA_TOKEN}`, 'Content-Type': 'application/json', 'Accept': 'application/json', ...options.headers } }); if (!response.ok) { const errorText = await response.text(); logger.error(`Gitea API Fehler: ${response.status} - ${errorText}`); throw new Error(`Gitea API Fehler: ${response.status}`); } return response.json(); } /** * Alle Repositories der Organisation abrufen */ async function listRepositories(options = {}) { try { const page = options.page || 1; const limit = options.limit || 50; // Repositories der Organisation abrufen const repos = await giteaFetch(`/orgs/${GITEA_ORG}/repos?page=${page}&limit=${limit}`); return { success: true, repositories: repos.map(repo => ({ id: repo.id, name: repo.name, fullName: repo.full_name, owner: repo.owner.login, description: repo.description || '', cloneUrl: repo.clone_url, htmlUrl: repo.html_url, defaultBranch: repo.default_branch, private: repo.private, fork: repo.fork, stars: repo.stars_count, forks: repo.forks_count, updatedAt: repo.updated_at, createdAt: repo.created_at })) }; } catch (error) { logger.error('Fehler beim Abrufen der Repositories:', error); return { success: false, error: error.message }; } } /** * Repository-Details abrufen */ async function getRepository(owner, repo) { try { const repoData = await giteaFetch(`/repos/${owner}/${repo}`); return { success: true, repository: { id: repoData.id, name: repoData.name, fullName: repoData.full_name, owner: repoData.owner.login, description: repoData.description || '', cloneUrl: repoData.clone_url, htmlUrl: repoData.html_url, defaultBranch: repoData.default_branch, private: repoData.private, fork: repoData.fork, stars: repoData.stars_count, forks: repoData.forks_count, size: repoData.size, updatedAt: repoData.updated_at, createdAt: repoData.created_at } }; } catch (error) { logger.error(`Fehler beim Abrufen des Repositories ${owner}/${repo}:`, error); return { success: false, error: error.message }; } } /** * Branches eines Repositories abrufen */ async function getRepositoryBranches(owner, repo) { try { const branches = await giteaFetch(`/repos/${owner}/${repo}/branches`); return { success: true, branches: branches.map(branch => ({ name: branch.name, commit: branch.commit?.id, protected: branch.protected })) }; } catch (error) { logger.error(`Fehler beim Abrufen der Branches für ${owner}/${repo}:`, error); return { success: false, error: error.message }; } } /** * Commits eines Repositories abrufen */ async function getRepositoryCommits(owner, repo, options = {}) { try { const page = options.page || 1; const limit = options.limit || 20; const branch = options.branch || ''; let endpoint = `/repos/${owner}/${repo}/commits?page=${page}&limit=${limit}`; if (branch) { endpoint += `&sha=${branch}`; } const commits = await giteaFetch(endpoint); return { success: true, commits: commits.map(commit => ({ sha: commit.sha, shortSha: commit.sha.substring(0, 7), message: commit.commit.message, author: commit.commit.author.name, email: commit.commit.author.email, date: commit.commit.author.date, htmlUrl: commit.html_url })) }; } catch (error) { logger.error(`Fehler beim Abrufen der Commits für ${owner}/${repo}:`, error); return { success: false, error: error.message }; } } /** * Neues Repository in der Organisation erstellen */ async function createRepository(name, options = {}) { try { // Repository unter der Organisation erstellen const repoData = await giteaFetch(`/orgs/${GITEA_ORG}/repos`, { method: 'POST', body: JSON.stringify({ name, description: options.description || '', private: options.private !== false, auto_init: options.autoInit !== false, default_branch: options.defaultBranch || 'main', readme: options.readme || 'Default' }) }); logger.info(`Repository in Organisation ${GITEA_ORG} erstellt: ${repoData.full_name}`); return { success: true, repository: { id: repoData.id, name: repoData.name, fullName: repoData.full_name, owner: repoData.owner.login, cloneUrl: repoData.clone_url, htmlUrl: repoData.html_url, defaultBranch: repoData.default_branch } }; } catch (error) { logger.error('Fehler beim Erstellen des Repositories:', error); return { success: false, error: error.message }; } } /** * Repository löschen */ async function deleteRepository(owner, repo) { try { await giteaFetch(`/repos/${owner}/${repo}`, { method: 'DELETE' }); logger.info(`Repository gelöscht: ${owner}/${repo}`); return { success: true }; } catch (error) { logger.error(`Fehler beim Löschen des Repositories ${owner}/${repo}:`, error); return { success: false, error: error.message }; } } /** * Authentifizierten Benutzer abrufen */ async function getCurrentUser() { try { const user = await giteaFetch('/user'); return { success: true, user: { id: user.id, login: user.login, fullName: user.full_name, email: user.email, avatarUrl: user.avatar_url } }; } catch (error) { logger.error('Fehler beim Abrufen des aktuellen Benutzers:', error); return { success: false, error: error.message }; } } /** * Prüft ob die Gitea-Verbindung funktioniert */ async function testConnection() { try { const result = await getCurrentUser(); return { success: result.success, connected: result.success, user: result.user, giteaUrl: GITEA_URL, organization: GITEA_ORG }; } catch (error) { return { success: false, connected: false, error: error.message, giteaUrl: GITEA_URL, organization: GITEA_ORG }; } } /** * Clone-URL mit Token für private Repos */ function getAuthenticatedCloneUrl(cloneUrl) { if (!GITEA_TOKEN) { return cloneUrl; } // Füge Token zur URL hinzu return cloneUrl.replace('https://', `https://${GITEA_TOKEN}@`); } /** * Gitea-URL ohne Token (für Anzeige) */ function getSafeCloneUrl(cloneUrl) { // Entferne Token aus URL falls vorhanden return cloneUrl.replace(/https:\/\/[^@]+@/, 'https://'); } /** * Repository-Einstellungen aktualisieren (z.B. default_branch ändern) */ async function updateRepository(owner, repo, options = {}) { try { const updateData = {}; if (options.defaultBranch) updateData.default_branch = options.defaultBranch; if (options.description !== undefined) updateData.description = options.description; if (options.private !== undefined) updateData.private = options.private; const repoData = await giteaFetch(`/repos/${owner}/${repo}`, { method: 'PATCH', body: JSON.stringify(updateData) }); logger.info(`Repository ${owner}/${repo} aktualisiert (default_branch: ${repoData.default_branch})`); return { success: true, repository: { id: repoData.id, name: repoData.name, fullName: repoData.full_name, defaultBranch: repoData.default_branch } }; } catch (error) { logger.error(`Fehler beim Aktualisieren des Repositories ${owner}/${repo}:`, error); return { success: false, error: error.message }; } } module.exports = { listRepositories, getRepository, getRepositoryBranches, getRepositoryCommits, createRepository, updateRepository, deleteRepository, getCurrentUser, testConnection, getAuthenticatedCloneUrl, getSafeCloneUrl, GITEA_URL, GITEA_ORG };