fix(gate): handle workflow name hints in gh:run gate discovery (bd-m8ew)
When a formula specifies a gate with id="release.yml", the AwaitID now properly functions as a workflow name hint: - gate discover: finds gates where AwaitID is empty OR non-numeric - gate discover: filters matching runs by workflow name when hint present - gate check: gracefully handles non-numeric AwaitID with clear message Added isNumericRunID/isNumericID helpers and tests for the new behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Executed-By: beads/crew/dave Rig: beads Role: crew
This commit is contained in:
@@ -199,6 +199,99 @@ func TestCheckBeadGate_TargetClosed(t *testing.T) {
|
||||
t.Log("Full integration testing requires routes.jsonl setup")
|
||||
}
|
||||
|
||||
func TestIsNumericID(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want bool
|
||||
}{
|
||||
// Numeric IDs
|
||||
{"12345", true},
|
||||
{"12345678901234567890", true},
|
||||
{"0", true},
|
||||
{"1", true},
|
||||
|
||||
// Non-numeric (workflow names, etc.)
|
||||
{"", false},
|
||||
{"release.yml", false},
|
||||
{"CI", false},
|
||||
{"release", false},
|
||||
{"123abc", false},
|
||||
{"abc123", false},
|
||||
{"12.34", false},
|
||||
{"-123", false},
|
||||
{"123-456", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.input, func(t *testing.T) {
|
||||
got := isNumericID(tt.input)
|
||||
if got != tt.want {
|
||||
t.Errorf("isNumericID(%q) = %v, want %v", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNeedsDiscovery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
awaitType string
|
||||
awaitID string
|
||||
want bool
|
||||
}{
|
||||
// gh:run gates
|
||||
{"gh:run empty await_id", "gh:run", "", true},
|
||||
{"gh:run workflow name hint", "gh:run", "release.yml", true},
|
||||
{"gh:run workflow name without ext", "gh:run", "CI", true},
|
||||
{"gh:run numeric run ID", "gh:run", "12345", false},
|
||||
{"gh:run large numeric ID", "gh:run", "12345678901234567890", false},
|
||||
|
||||
// Other gate types should not need discovery
|
||||
{"gh:pr gate", "gh:pr", "", false},
|
||||
{"timer gate", "timer", "", false},
|
||||
{"human gate", "human", "", false},
|
||||
{"bead gate", "bead", "rig:id", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gate := &types.Issue{
|
||||
AwaitType: tt.awaitType,
|
||||
AwaitID: tt.awaitID,
|
||||
}
|
||||
got := needsDiscovery(gate)
|
||||
if got != tt.want {
|
||||
t.Errorf("needsDiscovery(%q, %q) = %v, want %v",
|
||||
tt.awaitType, tt.awaitID, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWorkflowNameHint(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
awaitID string
|
||||
want string
|
||||
}{
|
||||
{"empty", "", ""},
|
||||
{"numeric ID", "12345", ""},
|
||||
{"workflow name", "release.yml", "release.yml"},
|
||||
{"workflow name yaml", "ci.yaml", "ci.yaml"},
|
||||
{"workflow name no ext", "CI", "CI"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gate := &types.Issue{AwaitID: tt.awaitID}
|
||||
got := getWorkflowNameHint(gate)
|
||||
if got != tt.want {
|
||||
t.Errorf("getWorkflowNameHint(%q) = %q, want %q", tt.awaitID, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// gateTestContainsIgnoreCase checks if haystack contains needle (case-insensitive)
|
||||
func gateTestContainsIgnoreCase(haystack, needle string) bool {
|
||||
return gateTestContains(gateTestLowerCase(haystack), gateTestLowerCase(needle))
|
||||
|
||||
Reference in New Issue
Block a user