diff --git a/ingestion/internal/gitea/gitea.go b/ingestion/internal/gitea/gitea.go index a37ef16..a3a87e6 100644 --- a/ingestion/internal/gitea/gitea.go +++ b/ingestion/internal/gitea/gitea.go @@ -109,15 +109,19 @@ func (c *Client) WriteFile(ctx context.Context, repo, path, content string) erro "message": "capture: " + path, "content": base64.StdEncoding.EncodeToString([]byte(content)), } + // Gitea contents API: POST creates a new file, PUT updates an existing + // one (PUT requires the current sha). Pick by whether the file exists. + method := http.MethodPost if sha != "" { - payload["sha"] = sha // update in place + method = http.MethodPut + payload["sha"] = sha } - status, body, err := c.request(ctx, http.MethodPut, cpath, payload) + status, body, err := c.request(ctx, method, cpath, payload) if err != nil { return err } if status < 200 || status >= 300 { - return fmt.Errorf("gitea PUT %s: status %d: %s", cpath, status, strings.TrimSpace(string(body))) + return fmt.Errorf("gitea %s %s: status %d: %s", method, cpath, status, strings.TrimSpace(string(body))) } return nil } diff --git a/ingestion/internal/gitea/gitea_test.go b/ingestion/internal/gitea/gitea_test.go index 0f193f1..3acca29 100644 --- a/ingestion/internal/gitea/gitea_test.go +++ b/ingestion/internal/gitea/gitea_test.go @@ -117,18 +117,20 @@ func TestErrorPathDoesNotLeakToken(t *testing.T) { } func TestWriteFileCreatesNewFile(t *testing.T) { - var getPath, putPath, putBody string + var getPath, postPath, postBody string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: getPath = r.URL.Path w.WriteHeader(http.StatusNotFound) // file does not exist yet - case http.MethodPut: - putPath = r.URL.Path + case http.MethodPost: // gitea contents API: POST = create + postPath = r.URL.Path b, _ := io.ReadAll(r.Body) - putBody = string(b) + postBody = string(b) w.WriteHeader(http.StatusCreated) _ = json.NewEncoder(w).Encode(map[string]any{"content": map[string]any{"html_url": "https://git/x"}}) + default: + t.Errorf("create must POST, got %s", r.Method) } })) defer srv.Close() @@ -137,10 +139,10 @@ func TestWriteFileCreatesNewFile(t *testing.T) { "ai-sessions", "summaries/claude-code/2026-06/2026-06-23-x-abcd1234.md", "# Summary\n\nbody\n") require.NoError(t, err) assert.Equal(t, "/api/v1/repos/mathias/ai-sessions/contents/summaries/claude-code/2026-06/2026-06-23-x-abcd1234.md", getPath) - assert.Equal(t, getPath, putPath) + assert.Equal(t, getPath, postPath) // base64 of the content, no sha on create. - assert.Contains(t, putBody, "IyBTdW1tYXJ5") // base64("# Summary") - assert.NotContains(t, putBody, `"sha"`) + assert.Contains(t, postBody, "IyBTdW1tYXJ5") // base64("# Summary") + assert.NotContains(t, postBody, `"sha"`) } func TestWriteFileUpdatesExisting(t *testing.T) {