Update from Git Manager GUI
This commit is contained in:
@@ -3,10 +3,96 @@
|
||||
// getGiteaRepoContents, getGiteaFileContent, uploadGiteaFile
|
||||
|
||||
const axios = require('axios');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
|
||||
// IPv4 bevorzugen – verhindert ETIMEDOUT wenn der Hostname nur per IPv6 erreichbar wäre
|
||||
// oder Node.js fälschlicherweise IPv6 vorranging versucht.
|
||||
const ipv4HttpAgent = new http.Agent({ family: 4, keepAlive: true });
|
||||
const ipv4HttpsAgent = new https.Agent({ family: 4, keepAlive: true });
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
httpAgent: ipv4HttpAgent,
|
||||
httpsAgent: ipv4HttpsAgent,
|
||||
});
|
||||
|
||||
function normalizeAndValidateBaseUrl(rawUrl) {
|
||||
const value = (rawUrl || '').trim();
|
||||
if (!value) {
|
||||
throw new Error('Gitea URL fehlt. Bitte tragen Sie eine URL ein.');
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(value);
|
||||
} catch (_) {
|
||||
throw new Error('Ungueltige Gitea URL. Beispiel fuer IPv6: http://[2001:db8::1]:3000');
|
||||
}
|
||||
|
||||
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||||
throw new Error('Gitea URL muss mit http:// oder https:// beginnen.');
|
||||
}
|
||||
|
||||
return value.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
function normalizeBase(url) {
|
||||
if (!url) return null;
|
||||
return url.replace(/\/$/, '');
|
||||
return normalizeAndValidateBaseUrl(url);
|
||||
}
|
||||
|
||||
async function checkGiteaConnection({ token, url, timeout = 8000 }) {
|
||||
const base = normalizeAndValidateBaseUrl(url);
|
||||
const started = Date.now();
|
||||
|
||||
const versionRes = await axiosInstance.get(`${base}/api/v1/version`, {
|
||||
timeout,
|
||||
validateStatus: () => true,
|
||||
headers: {
|
||||
'User-Agent': 'Git-Manager-GUI'
|
||||
}
|
||||
});
|
||||
|
||||
const latencyMs = Math.max(1, Date.now() - started);
|
||||
const apiReachable = versionRes.status >= 200 && versionRes.status < 500;
|
||||
|
||||
let authStatus = null;
|
||||
let authOk = false;
|
||||
if (token) {
|
||||
const userRes = await axiosInstance.get(`${base}/api/v1/user`, {
|
||||
timeout,
|
||||
validateStatus: () => true,
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'User-Agent': 'Git-Manager-GUI'
|
||||
}
|
||||
});
|
||||
authStatus = userRes.status;
|
||||
authOk = userRes.status >= 200 && userRes.status < 300;
|
||||
}
|
||||
|
||||
const serverVersion =
|
||||
(versionRes.data && (versionRes.data.version || versionRes.data.Version || versionRes.data.tag)) ||
|
||||
null;
|
||||
|
||||
return {
|
||||
ok: apiReachable && (!!token ? authOk : true),
|
||||
base,
|
||||
checks: {
|
||||
urlValid: true,
|
||||
apiReachable,
|
||||
authProvided: !!token,
|
||||
authOk
|
||||
},
|
||||
metrics: {
|
||||
latencyMs,
|
||||
versionStatus: versionRes.status,
|
||||
authStatus
|
||||
},
|
||||
server: {
|
||||
version: serverVersion
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function buildContentsUrl(base, owner, repo, p) {
|
||||
@@ -17,7 +103,7 @@ function buildContentsUrl(base, owner, repo, p) {
|
||||
|
||||
async function tryRequest(url, token, opts = {}) {
|
||||
try {
|
||||
const res = await axios.get(url, {
|
||||
const res = await axiosInstance.get(url, {
|
||||
headers: token ? { Authorization: `token ${token}` } : {},
|
||||
timeout: opts.timeout || 10000
|
||||
});
|
||||
@@ -40,7 +126,7 @@ async function createRepoGitHub({ name, token, auto_init = true, license = '', p
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post('https://api.github.com/user/repos', body, {
|
||||
const response = await axiosInstance.post('https://api.github.com/user/repos', body, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -99,7 +185,7 @@ async function createRepoGitea({ name, token, url, auto_init = true, license = '
|
||||
console.log('Request body:', JSON.stringify(body, null, 2));
|
||||
|
||||
try {
|
||||
const response = await axios.post(endpoint, body, {
|
||||
const response = await axiosInstance.post(endpoint, body, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
timeout: 15000 // 15 Sekunden Timeout
|
||||
});
|
||||
@@ -122,7 +208,7 @@ async function createRepoGitea({ name, token, url, auto_init = true, license = '
|
||||
};
|
||||
|
||||
try {
|
||||
const retryResponse = await axios.post(endpoint, bodyWithoutLicense, {
|
||||
const retryResponse = await axiosInstance.post(endpoint, bodyWithoutLicense, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
timeout: 15000
|
||||
});
|
||||
@@ -168,7 +254,7 @@ async function createRepoGitea({ name, token, url, auto_init = true, license = '
|
||||
|
||||
async function listGiteaRepos({ token, url }) {
|
||||
const endpoint = normalizeBase(url) + '/api/v1/user/repos';
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -335,8 +421,9 @@ async function uploadGiteaFile({ token, url, owner, repo, path, contentBase64, m
|
||||
const fetchSha = async () => {
|
||||
try {
|
||||
const existing = await getGiteaRepoContents({ token, url: base, owner, repo, path, ref: branchName });
|
||||
if (existing && existing.length > 0 && existing[0].sha) {
|
||||
return existing[0].sha;
|
||||
const items = existing && existing.items ? existing.items : (Array.isArray(existing) ? existing : []);
|
||||
if (items.length > 0 && items[0].sha) {
|
||||
return items[0].sha;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
@@ -350,11 +437,10 @@ async function uploadGiteaFile({ token, url, owner, repo, path, contentBase64, m
|
||||
const fileName = pathParts.pop();
|
||||
const dirPath = pathParts.join('/');
|
||||
|
||||
const list = await getGiteaRepoContents({ token, url: base, owner, repo, path: dirPath, ref: branchName });
|
||||
if (Array.isArray(list)) {
|
||||
const item = list.find(i => i.name === fileName);
|
||||
if (item && item.sha) return item.sha;
|
||||
}
|
||||
const result = await getGiteaRepoContents({ token, url: base, owner, repo, path: dirPath, ref: branchName });
|
||||
const list = result && result.items ? result.items : (Array.isArray(result) ? result : []);
|
||||
const item = list.find(i => i.name === fileName);
|
||||
if (item && item.sha) return item.sha;
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
@@ -385,7 +471,7 @@ async function uploadGiteaFile({ token, url, owner, repo, path, contentBase64, m
|
||||
console.log(`[Upload Debug] Datei: ${path}, Branch: ${branchName}, SHA: ${sha ? sha.substring(0, 8) : 'keine'}`);
|
||||
|
||||
try {
|
||||
const res = await axios.put(endpoint, body, {
|
||||
const res = await axiosInstance.put(endpoint, body, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
timeout: 30000 // 30 Sekunden Timeout für größere Dateien
|
||||
});
|
||||
@@ -478,7 +564,7 @@ async function getGiteaCommits({ token, url, owner, repo, branch = 'HEAD', page
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
params: {
|
||||
sha: branch,
|
||||
@@ -503,7 +589,7 @@ async function getGiteaCommit({ token, url, owner, repo, sha }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/commits/${sha}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -524,7 +610,7 @@ async function getGiteaCommitDiff({ token, url, owner, repo, sha }) {
|
||||
const endpoint = `${base}/${owner}/${repo}/commit/${sha}.diff`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -544,7 +630,7 @@ async function getGiteaCommitFiles({ token, url, owner, repo, sha }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/commits/${sha}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
|
||||
@@ -581,7 +667,7 @@ async function searchGiteaCommits({ token, url, owner, repo, query, branch = 'HE
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` },
|
||||
params: {
|
||||
sha: branch,
|
||||
@@ -614,7 +700,7 @@ async function getGiteaBranches({ token, url, owner, repo }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/branches`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -638,7 +724,7 @@ async function listGiteaReleases({ token, url, owner, repo }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -658,7 +744,7 @@ async function getGiteaRelease({ token, url, owner, repo, tag }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/tags/${encodeURIComponent(tag)}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint, {
|
||||
const response = await axiosInstance.get(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.data;
|
||||
@@ -687,7 +773,7 @@ async function createGiteaRelease({ token, url, owner, repo, data }) {
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await axios.post(endpoint, body, {
|
||||
const response = await axiosInstance.post(endpoint, body, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
@@ -747,7 +833,7 @@ async function editGiteaRelease({ token, url, owner, repo, releaseId, data }) {
|
||||
if (data.tag_name !== undefined) body.tag_name = data.tag_name;
|
||||
|
||||
try {
|
||||
const response = await axios.patch(endpoint, body, {
|
||||
const response = await axiosInstance.patch(endpoint, body, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
@@ -770,7 +856,7 @@ async function deleteGiteaRelease({ token, url, owner, repo, releaseId }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/${releaseId}`;
|
||||
|
||||
try {
|
||||
await axios.delete(endpoint, {
|
||||
await axiosInstance.delete(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return { ok: true };
|
||||
@@ -799,7 +885,7 @@ async function uploadReleaseAsset({ token, url, owner, repo, releaseId, filePath
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await axios.post(endpoint, formData, {
|
||||
const response = await axiosInstance.post(endpoint, formData, {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
...formData.getHeaders()
|
||||
@@ -824,7 +910,7 @@ async function deleteReleaseAsset({ token, url, owner, repo, assetId }) {
|
||||
const endpoint = `${base}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/assets/${assetId}`;
|
||||
|
||||
try {
|
||||
await axios.delete(endpoint, {
|
||||
await axiosInstance.delete(endpoint, {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return { ok: true };
|
||||
@@ -835,8 +921,10 @@ async function deleteReleaseAsset({ token, url, owner, repo, assetId }) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
normalizeAndValidateBaseUrl,
|
||||
createRepoGitHub,
|
||||
createRepoGitea,
|
||||
checkGiteaConnection,
|
||||
listGiteaRepos,
|
||||
getGiteaRepoContents,
|
||||
getGiteaFileContent,
|
||||
|
||||
Reference in New Issue
Block a user