feat(pr_merge): gate it like tbd_ship — green CI, unprotected base, exactly one risk/low issue (#74) (#76)
CD / Lint / Test / Vet (push) Successful in 15s
CD / Build & Import (push) Successful in 7s
CD / Deploy via GitOps (push) Skipped

Co-authored-by: Mathias <mthbqv@gmail.com>
This commit was merged in pull request #76.
This commit is contained in:
2026-10-08 06:18:07 +00:00
committed by mathias
parent d3faffc4c4
commit d1e501cc64
7 changed files with 529 additions and 85 deletions
+38
View File
@@ -1,6 +1,11 @@
package tools
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
"git.d-ma.be/mathias/gitea-mcp/internal/gitea"
@@ -98,3 +103,36 @@ func TestClassifyRisk(t *testing.T) {
})
}
}
// The merge gate needs a head commit to scope CI to and to bind the merge to: without one nothing merges.
func TestEvaluateMergeGate_UnknownHeadCommitNeverMerges(t *testing.T) {
green := []gitea.WorkflowRun{{Status: "completed", Conclusion: "success"}}
g := evaluateMergeGate("", green, &gitea.BranchProtection{}, riskLow)
if g.merge {
t.Fatalf("merge = true for an empty head sha (reason %q)", g.reason)
}
if !strings.Contains(g.reason, "head commit") {
t.Errorf("reason %q should name the head commit", g.reason)
}
if ok := evaluateMergeGate("abc", green, &gitea.BranchProtection{}, riskLow); !ok.merge {
t.Errorf("a known head sha with green CI and risk/low must still merge, got %q", ok.reason)
}
}
func TestPollRuns_NoShaMakesNoQuery(t *testing.T) {
var requests atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requests.Add(1)
_, _ = w.Write([]byte(`{"total_count":1,"workflow_runs":[{"id":1,"status":"completed","conclusion":"success"}]}`))
}))
defer srv.Close()
c := gitea.NewClient(srv.URL, "tok")
if runs := pollRuns(context.Background(), c, "o", "r", "", 0); len(runs) != 0 || requests.Load() != 0 {
t.Errorf("an empty sha must make no request and return no runs, got %d runs after %d requests", len(runs), requests.Load())
}
// positive control: with a sha the same server is asked, so the zero above means something
if runs := pollRuns(context.Background(), c, "o", "r", "abc", 0); len(runs) != 1 || requests.Load() != 1 {
t.Errorf("control: with a sha expected 1 run after 1 request, got %d runs after %d requests", len(runs), requests.Load())
}
}