feat(types): add RequiredSections() method to IssueType (bd-v2mr)
Foundation for opt-in template validation (bd-ou35). Returns recommended markdown sections per issue type: - Bug: Steps to Reproduce, Acceptance Criteria - Task/Feature: Acceptance Criteria - Epic: Success Criteria - Others: no requirements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
a9e70e3fe5
commit
e6ee7a6912
@@ -420,6 +420,37 @@ func (t IssueType) IsValid() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequiredSection describes a recommended section for an issue type.
|
||||||
|
// Used by bd lint and bd create --validate for template validation.
|
||||||
|
type RequiredSection struct {
|
||||||
|
Heading string // Markdown heading, e.g., "## Steps to Reproduce"
|
||||||
|
Hint string // Guidance for what to include
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiredSections returns the recommended sections for this issue type.
|
||||||
|
// Returns nil for types with no specific section requirements.
|
||||||
|
func (t IssueType) RequiredSections() []RequiredSection {
|
||||||
|
switch t {
|
||||||
|
case TypeBug:
|
||||||
|
return []RequiredSection{
|
||||||
|
{Heading: "## Steps to Reproduce", Hint: "Describe how to reproduce the bug"},
|
||||||
|
{Heading: "## Acceptance Criteria", Hint: "Define criteria to verify the fix"},
|
||||||
|
}
|
||||||
|
case TypeTask, TypeFeature:
|
||||||
|
return []RequiredSection{
|
||||||
|
{Heading: "## Acceptance Criteria", Hint: "Define criteria to verify completion"},
|
||||||
|
}
|
||||||
|
case TypeEpic:
|
||||||
|
return []RequiredSection{
|
||||||
|
{Heading: "## Success Criteria", Hint: "Define high-level success criteria"},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Chore, message, molecule, gate, agent, role, convoy, event, merge-request
|
||||||
|
// have no required sections
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AgentState represents the self-reported state of an agent
|
// AgentState represents the self-reported state of an agent
|
||||||
type AgentState string
|
type AgentState string
|
||||||
|
|
||||||
|
|||||||
@@ -414,6 +414,42 @@ func TestIssueTypeIsValid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssueTypeRequiredSections(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
issueType IssueType
|
||||||
|
expectCount int
|
||||||
|
expectHeading string // First heading if any
|
||||||
|
}{
|
||||||
|
{TypeBug, 2, "## Steps to Reproduce"},
|
||||||
|
{TypeFeature, 1, "## Acceptance Criteria"},
|
||||||
|
{TypeTask, 1, "## Acceptance Criteria"},
|
||||||
|
{TypeEpic, 1, "## Success Criteria"},
|
||||||
|
{TypeChore, 0, ""},
|
||||||
|
{TypeMessage, 0, ""},
|
||||||
|
{TypeMolecule, 0, ""},
|
||||||
|
{TypeGate, 0, ""},
|
||||||
|
{TypeAgent, 0, ""},
|
||||||
|
{TypeRole, 0, ""},
|
||||||
|
{TypeConvoy, 0, ""},
|
||||||
|
{TypeEvent, 0, ""},
|
||||||
|
{TypeMergeRequest, 0, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(string(tt.issueType), func(t *testing.T) {
|
||||||
|
sections := tt.issueType.RequiredSections()
|
||||||
|
if len(sections) != tt.expectCount {
|
||||||
|
t.Errorf("IssueType(%q).RequiredSections() returned %d sections, want %d",
|
||||||
|
tt.issueType, len(sections), tt.expectCount)
|
||||||
|
}
|
||||||
|
if tt.expectCount > 0 && sections[0].Heading != tt.expectHeading {
|
||||||
|
t.Errorf("IssueType(%q).RequiredSections()[0].Heading = %q, want %q",
|
||||||
|
tt.issueType, sections[0].Heading, tt.expectHeading)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAgentStateIsValid(t *testing.T) {
|
func TestAgentStateIsValid(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in New Issue
Block a user