Update from Git Manager GUI
This commit is contained in:
@@ -305,11 +305,366 @@ async function uploadGiteaFile({ token, url, owner, repo, path, contentBase64, m
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================
|
||||
COMMIT HISTORY FUNCTIONS (GITEA)
|
||||
================================ */
|
||||
|
||||
/**
|
||||
* Get commit history from Gitea repository
|
||||
*/
|
||||
async function getGiteaCommits({ token, url, owner, repo, branch = 'main', page = 1, limit = 50 }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
params: {
|
||||
sha: branch,
|
||||
page,
|
||||
limit
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('getGiteaCommits error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific commit with diff
|
||||
*/
|
||||
async function getGiteaCommit({ token, url, owner, repo, sha }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/commits/${sha}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('getGiteaCommit error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit diff/patch
|
||||
*/
|
||||
async function getGiteaCommitDiff({ token, url, owner, repo, sha }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
// Gitea returns diff in the commit endpoint with .diff extension
|
||||
const endpoint = `${base}/${owner}/${repo}/commit/${sha}.diff`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('getGiteaCommitDiff error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit file changes/stats
|
||||
*/
|
||||
async function getGiteaCommitFiles({ token, url, owner, repo, sha }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/commits/${sha}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
|
||||
// Gitea commit response includes stats
|
||||
const commit = response.data;
|
||||
|
||||
// Normalize files to match local git format
|
||||
const files = (commit.files || []).map(f => ({
|
||||
file: f.filename || f.file || '',
|
||||
changes: (f.additions || 0) + (f.deletions || 0),
|
||||
insertions: f.additions || 0,
|
||||
deletions: f.deletions || 0,
|
||||
binary: f.binary || false
|
||||
}));
|
||||
|
||||
return {
|
||||
files,
|
||||
stats: commit.stats || { additions: 0, deletions: 0, total: 0 }
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('getGiteaCommitFiles error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search commits in Gitea repository
|
||||
*/
|
||||
async function searchGiteaCommits({ token, url, owner, repo, query, branch = 'main' }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
// Gitea doesn't have direct commit search, so we get commits and filter
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
params: {
|
||||
sha: branch,
|
||||
limit: 100 // Get more for searching
|
||||
}
|
||||
});
|
||||
|
||||
// Filter commits by query
|
||||
const lowerQuery = query.toLowerCase();
|
||||
const filtered = response.data.filter(commit => {
|
||||
const message = (commit.commit?.message || '').toLowerCase();
|
||||
const author = (commit.commit?.author?.name || '').toLowerCase();
|
||||
return message.includes(lowerQuery) || author.includes(lowerQuery);
|
||||
});
|
||||
|
||||
return filtered;
|
||||
} catch (err) {
|
||||
console.error('searchGiteaCommits error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get branches for branch graph visualization
|
||||
*/
|
||||
async function getGiteaBranches({ token, url, owner, repo }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/branches`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('getGiteaBranches error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================
|
||||
RELEASE MANAGEMENT FUNCTIONS
|
||||
================================ */
|
||||
|
||||
/**
|
||||
* List all releases for a repository
|
||||
*/
|
||||
async function listGiteaReleases({ token, url, owner, repo }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('listGiteaReleases error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific release by tag
|
||||
*/
|
||||
async function getGiteaRelease({ token, url, owner, repo, tag }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/tags/${encodeURIComponent(tag)}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('getGiteaRelease error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new release
|
||||
*/
|
||||
async function createGiteaRelease({ token, url, owner, repo, data }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases`;
|
||||
|
||||
const body = {
|
||||
tag_name: data.tag_name,
|
||||
name: data.name || data.tag_name,
|
||||
body: data.body || '',
|
||||
draft: data.draft || false,
|
||||
prerelease: data.prerelease || false,
|
||||
target_commitish: data.target_commitish || 'main'
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await axios.post(endpoint, body, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('createGiteaRelease error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit/update an existing release
|
||||
*/
|
||||
async function editGiteaRelease({ token, url, owner, repo, releaseId, data }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/${releaseId}`;
|
||||
|
||||
const body = {};
|
||||
if (data.name !== undefined) body.name = data.name;
|
||||
if (data.body !== undefined) body.body = data.body;
|
||||
if (data.draft !== undefined) body.draft = data.draft;
|
||||
if (data.prerelease !== undefined) body.prerelease = data.prerelease;
|
||||
if (data.tag_name !== undefined) body.tag_name = data.tag_name;
|
||||
|
||||
try {
|
||||
const response = await axios.patch(endpoint, body, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('editGiteaRelease error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a release
|
||||
*/
|
||||
async function deleteGiteaRelease({ token, url, owner, repo, releaseId }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/${releaseId}`;
|
||||
|
||||
try {
|
||||
await axios.delete(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
console.error('deleteGiteaRelease error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a release asset (attachment)
|
||||
* Note: Gitea uses multipart/form-data for asset uploads
|
||||
*/
|
||||
async function uploadReleaseAsset({ token, url, owner, repo, releaseId, filePath, fileName }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const FormData = require('form-data');
|
||||
const fs = require('fs');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/${releaseId}/assets`;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('attachment', fs.createReadStream(filePath), {
|
||||
filename: fileName || require('path').basename(filePath)
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await axios.post(endpoint, formData, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
...formData.getHeaders()
|
||||
},
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('uploadReleaseAsset error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a release asset
|
||||
*/
|
||||
async function deleteReleaseAsset({ token, url, owner, repo, assetId }) {
|
||||
const base = normalizeBase(url);
|
||||
if (!base) throw new Error('Invalid Gitea base URL');
|
||||
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/assets/${assetId}`;
|
||||
|
||||
try {
|
||||
await axios.delete(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
console.error('deleteReleaseAsset error:', err.response?.data || err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createRepoGitHub,
|
||||
createRepoGitea,
|
||||
listGiteaRepos,
|
||||
getGiteaRepoContents,
|
||||
getGiteaFileContent,
|
||||
uploadGiteaFile
|
||||
uploadGiteaFile,
|
||||
// Commit History
|
||||
getGiteaCommits,
|
||||
getGiteaCommit,
|
||||
getGiteaCommitDiff,
|
||||
getGiteaCommitFiles,
|
||||
searchGiteaCommits,
|
||||
getGiteaBranches,
|
||||
// Release Management
|
||||
listGiteaReleases,
|
||||
getGiteaRelease,
|
||||
createGiteaRelease,
|
||||
editGiteaRelease,
|
||||
deleteGiteaRelease,
|
||||
uploadReleaseAsset,
|
||||
deleteReleaseAsset
|
||||
};
|
||||
Reference in New Issue
Block a user