Files
agent-tools/internal/agent/watch_test.go
T
unkin-agent d78644d173
ci/woodpecker/pr/build Pipeline failed
ci/woodpecker/pr/test Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline failed
Add agentpr and watchpr CLI tools
agentpr manages PRs/comments/whoami as unkin-agent (Vault AppRole -> gitea creds
-> Gitea API), fixing tea's post-as-Ben default. watchpr polls PRs and alerts
only on merge/close, human comment, CI failure, or lost mergeability.

- cobra multi-binary layout mirroring node-lookup (cmd/ + internal/)
- Makefile (build, patch|minor|major, completions, rpm), nfpm RPM with both
  binaries + bash/zsh/fish completions, woodpecker CI publishing to rpm-internal
- unit tests for parsing, meaningful-change detection, and the Vault+Gitea client
2026-08-12 21:37:09 +10:00

117 lines
2.9 KiB
Go

package agent
import "testing"
func base() PRState {
return PRState{
Ref: PRRef{Owner: "unkin", Repo: "repo", Number: 1},
State: "open",
Merged: false,
HeadSHA: "abc123",
Mergeable: true,
CIStatus: "pending",
NonAgentComments: 0,
}
}
func TestMeaningfulChange(t *testing.T) {
tests := []struct {
name string
mutate func(s *PRState)
wantChange bool
}{
{
name: "no change",
mutate: func(s *PRState) {},
wantChange: false,
},
{
name: "CI pending to success is benign",
mutate: func(s *PRState) { s.CIStatus = "success" },
wantChange: false,
},
{
name: "open to merged alerts",
mutate: func(s *PRState) { s.Merged = true; s.State = "closed" },
wantChange: true,
},
{
name: "open to closed without merge alerts",
mutate: func(s *PRState) { s.State = "closed" },
wantChange: true,
},
{
name: "new non-agent comment alerts",
mutate: func(s *PRState) { s.NonAgentComments = 1 },
wantChange: true,
},
{
name: "CI to failure alerts",
mutate: func(s *PRState) { s.CIStatus = "failure" },
wantChange: true,
},
{
name: "CI to error alerts",
mutate: func(s *PRState) { s.CIStatus = "error" },
wantChange: true,
},
{
name: "lost mergeability alerts",
mutate: func(s *PRState) { s.Mergeable = false },
wantChange: true,
},
{
name: "new head sha alone is benign",
mutate: func(s *PRState) { s.HeadSHA = "def456" },
wantChange: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
prev := base()
cur := base()
tt.mutate(&cur)
got, reason := MeaningfulChange(prev, cur)
if got != tt.wantChange {
t.Errorf("MeaningfulChange() = %v (%q), want %v", got, reason, tt.wantChange)
}
if got && reason == "" {
t.Errorf("change reported without a reason")
}
})
}
}
// A comment that only the agent posts must not alert: the non-agent count is
// unchanged, so MeaningfulChange sees nothing.
func TestMeaningfulChangeAgentCommentIgnored(t *testing.T) {
prev := base()
cur := base() // agent commented, but NonAgentComments stayed 0
if got, _ := MeaningfulChange(prev, cur); got {
t.Errorf("agent-only comment should not alert")
}
}
// Once CI is already failing, staying failed must not re-alert.
func TestMeaningfulChangeStaysFailed(t *testing.T) {
prev := base()
prev.CIStatus = "failure"
cur := base()
cur.CIStatus = "failure"
if got, _ := MeaningfulChange(prev, cur); got {
t.Errorf("CI staying failed should not re-alert")
}
}
func TestCountNonAgentComments(t *testing.T) {
comments := []Comment{
{User: User{Login: "unkin-agent"}},
{User: User{Login: "ben"}},
{User: User{Login: "unkin-agent"}},
{User: User{Login: "reviewer"}},
}
if n := countNonAgentComments(comments, "unkin-agent"); n != 2 {
t.Errorf("countNonAgentComments = %d, want 2", n)
}
}