diff --git a/src/GiteaClient.gs b/src/GiteaClient.gs new file mode 100644 index 0000000..5734361 --- /dev/null +++ b/src/GiteaClient.gs @@ -0,0 +1,106 @@ +/** + * GiteaClient - Low-level API wrapper for Gitea Git Hosting + */ + +/** + * Helper to ensure the base URL always points to the Gitea API root (/api/v1) + * @return {string} Normalized API base URL + */ +function getGiteaApiBaseUrl_() { + const config = getGiteaConfig(); + let baseUrl = config.baseUrl.replace(/\/$/, ''); // Remove trailing slash + + // Ensure the URL ends with /api/v1 + if (!baseUrl.endsWith('/api/v1')) { + baseUrl += '/api/v1'; + } + + return baseUrl; +} + +function giteaRequest_(method, path, payload = null) { + const apiBaseUrl = getGiteaApiBaseUrl_(); + const config = getGiteaConfig(); + + // Ensure path starts with a single slash + const normalizedPath = path.startsWith('/') ? path : '/' + path; + const url = `${apiBaseUrl}${normalizedPath}`; + + console.log(`Gitea Request: [${method}] ${url}`); + + const options = { + method: method, + headers: { + 'Authorization': `token ${config.token}`, + 'Content-Type': 'application/json' + }, + muteHttpExceptions: true + }; + + if (payload) { + options.payload = JSON.stringify(payload); + } + + try { + const response = UrlFetchApp.fetch(url, options); + const code = response.getResponseCode(); + const rawContent = response.getContentText(); + + let json; + try { + json = JSON.parse(rawContent); + } catch (e) { + json = null; // Not a JSON response + } + + if (code >= 200 && code < 300) { + return { ok: true, data: json || rawContent }; + } + + // Return structured error with raw body if JSON parsing failed + return { + ok: false, + message: json && json.message ? json.message : `Gitea API Error ${code}`, + code: code, + rawBody: rawContent + }; + } catch (e) { + return { ok: false, message: `Gitea Connection Error: ${e.message}` }; + } +} + +function getGiteaRepo() { + const config = getGiteaConfig(); + // Path is relative to /api/v1 + return giteaRequest_('GET', `/repos/${config.owner}/${config.repo}`); +} + +function createGiteaIssue(title, body) { + const config = getGiteaConfig(); + return giteaRequest_('POST', `/repos/${config.owner}/${config.repo}/issues`, { + title: title, + body: body + }); +} + +function createOrUpdateRepoFile(path, content, message, branch) { + const config = getGiteaConfig(); + const targetBranch = branch || config.branch; + + // Gitea requires SHA for updates. This is a simplified boilerplate. + return giteaRequest_('POST', `/repos/${config.owner}/${config.repo}/contents/${path}`, { + content: content, + message: message, + branch: targetBranch + }); +} + +function createReleaseTag(tagName, name, body, target) { + const config = getGiteaConfig(); + return giteaRequest_('POST', `/repos/${config.owner}/${config.repo}/releases`, { + tag_name: tagName, + name: name, + body: body, + target_commitish: target || config.branch + }); +}