buildEventAwareCommandCondition creates a condition that only applies command checks to comment-related events commandNames: list of command names that can trigger this workflow commandEvents: list of event identifiers where command should be active (nil = all events)
(commandNames []string, commandEvents []string, hasOtherEvents bool)
| 20 | // commandNames: list of command names that can trigger this workflow |
| 21 | // commandEvents: list of event identifiers where command should be active (nil = all events) |
| 22 | func buildEventAwareCommandCondition(commandNames []string, commandEvents []string, hasOtherEvents bool) (ConditionNode, error) { |
| 23 | commandLog.Printf("Building event-aware command condition: commands=%v, event_count=%d, has_other_events=%t", |
| 24 | commandNames, len(commandEvents), hasOtherEvents) |
| 25 | |
| 26 | if len(commandNames) == 0 { |
| 27 | return nil, errors.New("no command names provided") |
| 28 | } |
| 29 | |
| 30 | // Get the filtered events where command should be active |
| 31 | filteredEvents := FilterCommentEvents(commandEvents) |
| 32 | eventNames := GetCommentEventNames(filteredEvents) |
| 33 | commandLog.Printf("Filtered command events: commands=%v, filtered_count=%d", commandNames, len(eventNames)) |
| 34 | |
| 35 | // Build command checks for different content sources based on filtered events |
| 36 | var commandChecks []ConditionNode |
| 37 | |
| 38 | // Check which events are enabled |
| 39 | hasIssues := slices.Contains(eventNames, "issues") |
| 40 | hasIssueComment := slices.Contains(eventNames, "issue_comment") |
| 41 | hasPRComment := slices.Contains(eventNames, "pull_request_comment") |
| 42 | hasPR := slices.Contains(eventNames, "pull_request") |
| 43 | hasPRReview := slices.Contains(eventNames, "pull_request_review_comment") |
| 44 | hasDiscussion := slices.Contains(eventNames, "discussion") |
| 45 | hasDiscussionComment := slices.Contains(eventNames, "discussion_comment") |
| 46 | |
| 47 | // Helper function to build OR condition for multiple command checks |
| 48 | // Uses strict matching: command at start of line only |
| 49 | buildMultiCommandCheck := func(bodyAccessor string) ConditionNode { |
| 50 | var commandOrChecks []ConditionNode |
| 51 | for _, commandName := range commandNames { |
| 52 | if isWildcardCommandName(commandName) { |
| 53 | commandPrefix := "/" + strings.TrimSuffix(commandName, "*") |
| 54 | commandOrChecks = append(commandOrChecks, BuildFunctionCall("startsWith", |
| 55 | BuildPropertyAccess(bodyAccessor), |
| 56 | BuildStringLiteral(commandPrefix), |
| 57 | )) |
| 58 | continue |
| 59 | } |
| 60 | |
| 61 | commandText := "/" + commandName |
| 62 | commandWithSpace := fmt.Sprintf("/%s ", commandName) |
| 63 | commandWithNewline := fmt.Sprintf("/%s\n", commandName) |
| 64 | |
| 65 | // Check for exact match (command without arguments) |
| 66 | exactMatch := BuildEquals( |
| 67 | BuildPropertyAccess(bodyAccessor), |
| 68 | BuildStringLiteral(commandText), |
| 69 | ) |
| 70 | |
| 71 | // Check for command with arguments (starts with "/<command> ") |
| 72 | startsWithMatch := BuildFunctionCall("startsWith", |
| 73 | BuildPropertyAccess(bodyAccessor), |
| 74 | BuildStringLiteral(commandWithSpace), |
| 75 | ) |
| 76 | |
| 77 | // Check for command followed by a newline (e.g. bot comments that append metadata after the command) |
| 78 | startsWithNewlineMatch := BuildFunctionCall("startsWith", |
| 79 | BuildPropertyAccess(bodyAccessor), |
no test coverage detected