vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Filter workflow events by mentions and assignment
727df38613897e6ffd56e1df05a2f674174bf547 · Keenan Nemetz · 8d ago · parent eb07ff56
Filter workflow events by mentions and assignment Add mentioned, replied-to, assigned-to, and author filters to issue, comment, and change-request triggers. Move the role vocabulary into core/role so author.role is validated without importing the access store, and pin mentions, reply authors, and assignee changes in the event payload.
metadata/mentions_test.go +52
| @@ -0,0 +1,52 @@ | |||
| 1 | package metadata | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "reflect" | ||
| 5 | "strings" | ||
| 6 | "testing" | ||
| 7 | ) | ||
| 8 | |||
| 9 | func TestMentions(t *testing.T) { | ||
| 10 | t.Parallel() | ||
| 11 | cases := []struct { | ||
| 12 | name string | ||
| 13 | body string | ||
| 14 | want []string | ||
| 15 | }{ | ||
| 16 | {"plain", "Please ask @coding-agent to look.", []string{"coding-agent"}}, | ||
| 17 | {"case is folded", "Ask @Coding-Agent.", []string{"coding-agent"}}, | ||
| 18 | {"several are sorted and unique", "@wilbur and @keenan and @wilbur", []string{"keenan", "wilbur"}}, | ||
| 19 | {"email is not a mention", "mail me at user@example.com", nil}, | ||
| 20 | {"url is not a mention", "see https://example.test/@coding-agent", nil}, | ||
| 21 | {"escaped is not a mention", `write \@coding-agent literally`, nil}, | ||
| 22 | {"inline code is not a mention", "use `@coding-agent` in a sample", nil}, | ||
| 23 | {"fenced code is not a mention", "```\n@coding-agent\n```\n", nil}, | ||
| 24 | {"fence with language is not a mention", "~~~yaml\n# @coding-agent\n~~~\n", nil}, | ||
| 25 | {"too short", "hello @a", nil}, | ||
| 26 | {"longest valid", "hello @" + strings.Repeat("a", 32), []string{strings.Repeat("a", 32)}}, | ||
| 27 | {"too long", "hello @" + strings.Repeat("a", 33), nil}, | ||
| 28 | {"punctuation after", "thanks @keenan!", []string{"keenan"}}, | ||
| 29 | {"start of line", "@coding-agent please", []string{"coding-agent"}}, | ||
| 30 | } | ||
| 31 | for _, tc := range cases { | ||
| 32 | t.Run(tc.name, func(t *testing.T) { | ||
| 33 | t.Parallel() | ||
| 34 | if got := Mentions(tc.body); !reflect.DeepEqual(got, tc.want) { | ||
| 35 | t.Fatalf("Mentions(%q) = %v, want %v", tc.body, got, tc.want) | ||
| 36 | } | ||
| 37 | }) | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | func TestMentionsAreBounded(t *testing.T) { | ||
| 42 | t.Parallel() | ||
| 43 | var body strings.Builder | ||
| 44 | for i := 0; i < MaxMentions+5; i++ { | ||
| 45 | body.WriteString("@agent") | ||
| 46 | body.WriteString(string(rune('a' + i%26))) | ||
| 47 | body.WriteString(" ") | ||
| 48 | } | ||
| 49 | if got := Mentions(body.String()); len(got) > MaxMentions { | ||
| 50 | t.Fatalf("Mentions returned %d names, limit %d", len(got), MaxMentions) | ||
| 51 | } | ||
| 52 | } | ||