Files
gitea-mcp/internal/gitea/workflows_test.go
T
mathiasandClaude Opus 4.8 4ebea7d023
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 21s
CD / Deploy via GitOps (push) Has been skipped
fix(workflow_run_trigger): 204 dispatch is success; resolve run via listing (#41)
Gitea's workflow_dispatch endpoint returns 204 No Content with no Location
header. DispatchWorkflow required that header, so every successful dispatch
errored with "missing Location header" and never yielded a run ID — making
the tool unusable for CAD dispatch.

- DispatchWorkflow now returns error-only; 204 = success, no Location needed.
  Body already carried ref+inputs; kept and covered by test.
- Tool snapshots the newest existing workflow_dispatch run before dispatch,
  then polls ListWorkflowRuns after and returns the newest run with ID above
  that baseline (avoids returning a stale prior run). Falls back to an honest
  "dispatched, run not yet registered" result rather than failing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 21:12:45 +02:00

83 lines
2.6 KiB
Go

package gitea_test
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"
"gitea.d-ma.be/mathias/gitea-mcp/internal/gitea"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Gitea's dispatch endpoint returns 204 No Content with NO Location header.
// Dispatch must succeed and forward ref+inputs in the body; the run ID is
// resolved separately by the tool via ListWorkflowRuns.
func TestDispatchWorkflow(t *testing.T) {
var gotBody []byte
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/v1/repos/o/r/actions/workflows/ci.yml/dispatches", r.URL.Path)
var err error
gotBody, err = io.ReadAll(r.Body)
assert.NoError(t, err)
// No Location header — matches real Gitea.
w.WriteHeader(http.StatusNoContent)
}))
defer srv.Close()
c := gitea.NewClient(srv.URL, "tok")
err := c.DispatchWorkflow(context.Background(), "o", "r", "ci.yml", gitea.DispatchWorkflowArgs{
Ref: "main",
Inputs: map[string]any{"env": "prod"},
})
require.NoError(t, err)
var body map[string]any
require.NoError(t, json.Unmarshal(gotBody, &body))
assert.Equal(t, "main", body["ref"])
inputs, ok := body["inputs"].(map[string]any)
require.True(t, ok)
assert.Equal(t, "prod", inputs["env"])
}
func TestDispatchWorkflowError404(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
}))
defer srv.Close()
c := gitea.NewClient(srv.URL, "tok")
err := c.DispatchWorkflow(context.Background(), "o", "r", "ci.yml", gitea.DispatchWorkflowArgs{Ref: "main"})
require.Error(t, err)
assert.True(t, errors.Is(err, gitea.ErrNotFound))
}
func TestGetWorkflowRun(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/v1/repos/o/r/actions/runs/789", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{
"id":789,
"status":"completed",
"conclusion":"success",
"started_at":"2026-05-04T10:00:00Z",
"html_url":"http://gitea.example/o/r/actions/runs/789"
}`))
}))
defer srv.Close()
c := gitea.NewClient(srv.URL, "tok")
run, err := c.GetWorkflowRun(context.Background(), "o", "r", 789)
require.NoError(t, err)
assert.Equal(t, int64(789), run.ID)
assert.Equal(t, "completed", run.Status)
assert.Equal(t, "success", run.Conclusion)
assert.Equal(t, "2026-05-04T10:00:00Z", run.StartedAt)
assert.Equal(t, "http://gitea.example/o/r/actions/runs/789", run.HTMLURL)
}