fix: Gitea push 404 — add branch:main payload, handle 409 empty repo, clearer settings
- lib/git.ts: add branch:"main" to Gitea POST payload (required when repo has no branch yet or is freshly initialized); treat 409 on GET same as 404 (empty repo has no tree, Gitea returns 409 Conflict — proceed to create first file) - lib/git.ts: improve 404 error hint with actionable checklist (URL format, owner/repo names, token scope, repo existence) - settings.tsx: add Gitea info card clarifying URL format (no /api/v1), token format (raw value only, no "Bearer" prefix), repo initialization requirement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+21
-2
@@ -402,6 +402,25 @@ export default function SettingsScreen() {
|
|||||||
|
|
||||||
{gitProvider === "gitea" && (
|
{gitProvider === "gitea" && (
|
||||||
<>
|
<>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
backgroundColor: Colors.surface,
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 12,
|
||||||
|
marginBottom: 14,
|
||||||
|
borderLeftWidth: 3,
|
||||||
|
borderLeftColor: Colors.text2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={{ color: Colors.text2, fontSize: 12, lineHeight: 18 }}>
|
||||||
|
<Text style={{ fontWeight: "700" }}>Instance URL</Text>
|
||||||
|
{" — base URL only, no trailing slash, no /api/v1.\n"}
|
||||||
|
<Text style={{ fontWeight: "700" }}>Token</Text>
|
||||||
|
{" — Gitea PAT with write:repository scope. Paste the token value only (no \"Bearer\" prefix).\n"}
|
||||||
|
<Text style={{ fontWeight: "700" }}>Repository</Text>
|
||||||
|
{" — must have at least one commit (initialize it with a README if empty)."}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
<Field
|
<Field
|
||||||
label="Instance URL"
|
label="Instance URL"
|
||||||
value={giteaUrl}
|
value={giteaUrl}
|
||||||
@@ -410,10 +429,10 @@ export default function SettingsScreen() {
|
|||||||
url
|
url
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label="Token"
|
label="Token (PAT, write:repository)"
|
||||||
value={giteaToken}
|
value={giteaToken}
|
||||||
onChange={setGiteaToken}
|
onChange={setGiteaToken}
|
||||||
placeholder="Bearer token"
|
placeholder="paste token value here"
|
||||||
secure
|
secure
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
|
|||||||
+10
-2
@@ -71,7 +71,10 @@ async function pushGitea(
|
|||||||
if (existing.ok) {
|
if (existing.ok) {
|
||||||
const data = await existing.json() as { sha?: string };
|
const data = await existing.json() as { sha?: string };
|
||||||
sha = data.sha;
|
sha = data.sha;
|
||||||
} else if (existing.status !== 404) {
|
} else if (existing.status === 404 || existing.status === 409) {
|
||||||
|
// 404 = file not found (normal for first push)
|
||||||
|
// 409 = repo is empty / no branch yet — proceed, we'll create with branch:"main"
|
||||||
|
} else {
|
||||||
const body = await existing.text();
|
const body = await existing.text();
|
||||||
return { success: false, error: `GET ${existing.status}: ${body.slice(0, 200)}` };
|
return { success: false, error: `GET ${existing.status}: ${body.slice(0, 200)}` };
|
||||||
}
|
}
|
||||||
@@ -79,6 +82,7 @@ async function pushGitea(
|
|||||||
const payload: Record<string, string> = {
|
const payload: Record<string, string> = {
|
||||||
message: `incident: ${incident.title}`,
|
message: `incident: ${incident.title}`,
|
||||||
content: base64Content,
|
content: base64Content,
|
||||||
|
branch: "main",
|
||||||
};
|
};
|
||||||
if (sha) payload.sha = sha;
|
if (sha) payload.sha = sha;
|
||||||
|
|
||||||
@@ -94,7 +98,11 @@ async function pushGitea(
|
|||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const body = await res.text();
|
const body = await res.text();
|
||||||
return { success: false, error: `HTTP ${res.status}: ${body.slice(0, 300)}` };
|
let hint = "";
|
||||||
|
if (res.status === 404) {
|
||||||
|
hint = "\n\nCheck: instance URL (no /api/v1), owner and repo names are exact, token has write:repository scope, and the repo exists on Gitea.";
|
||||||
|
}
|
||||||
|
return { success: false, error: `HTTP ${res.status}: ${body.slice(0, 300)}${hint}` };
|
||||||
}
|
}
|
||||||
const data = await res.json() as { content?: { html_url?: string } };
|
const data = await res.json() as { content?: { html_url?: string } };
|
||||||
return { success: true, url: data.content?.html_url };
|
return { success: true, url: data.content?.html_url };
|
||||||
|
|||||||
Reference in New Issue
Block a user