Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pkg/workflow/copilot_participant_steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package workflow

import (
"fmt"

"github.com/githubnext/gh-aw/pkg/logger"
)

var copilotParticipantLog = logger.New("workflow:copilot_participant_steps")

// CopilotParticipantConfig holds configuration for generating Copilot participant steps
type CopilotParticipantConfig struct {
// Participants is the list of users/bots to assign/review
Expand All @@ -25,7 +29,10 @@ type CopilotParticipantConfig struct {
// buildCopilotParticipantSteps generates steps for adding Copilot participants (assignees or reviewers)
// This function extracts the common logic between issue assignees and PR reviewers
func buildCopilotParticipantSteps(config CopilotParticipantConfig) []string {
copilotParticipantLog.Printf("Building Copilot participant steps: type=%s, count=%d", config.ParticipantType, len(config.Participants))

if len(config.Participants) == 0 {
copilotParticipantLog.Print("No participants to add, returning empty steps")
return nil
}

Expand All @@ -50,15 +57,19 @@ func buildCopilotParticipantSteps(config CopilotParticipantConfig) []string {
// Use Copilot token preference if adding copilot as participant, otherwise use regular token
var effectiveToken string
if hasCopilotParticipant {
copilotParticipantLog.Print("Using Copilot token preference")
effectiveToken = getEffectiveCopilotGitHubToken(config.CustomToken, getEffectiveCopilotGitHubToken(config.SafeOutputsToken, config.WorkflowToken))
} else {
copilotParticipantLog.Print("Using regular GitHub token")
effectiveToken = getEffectiveGitHubToken(config.CustomToken, getEffectiveGitHubToken(config.SafeOutputsToken, config.WorkflowToken))
}

// Generate participant-specific steps
if config.ParticipantType == "assignee" {
copilotParticipantLog.Printf("Generating issue assignee steps for %d participants", len(config.Participants))
steps = append(steps, buildIssueAssigneeSteps(config, effectiveToken)...)
} else if config.ParticipantType == "reviewer" {
copilotParticipantLog.Printf("Generating PR reviewer steps for %d participants", len(config.Participants))
steps = append(steps, buildPRReviewerSteps(config, effectiveToken)...)
}

Expand Down
17 changes: 17 additions & 0 deletions pkg/workflow/manual_approval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,36 @@ package workflow

import (
"fmt"

"github.com/githubnext/gh-aw/pkg/logger"
)

var manualApprovalLog = logger.New("workflow:manual_approval")

// extractManualApprovalFromOn extracts the manual-approval value from the on: section
func (c *Compiler) extractManualApprovalFromOn(frontmatter map[string]any) (string, error) {
onSection, exists := frontmatter["on"]
if !exists {
manualApprovalLog.Print("No on: section found in frontmatter")
return "", nil
}

// Handle different formats of the on: section
switch on := onSection.(type) {
case string:
// Simple string format like "on: push" - no manual-approval possible
manualApprovalLog.Printf("on: section is simple string format: %s", on)
return "", nil
case map[string]any:
// Complex object format - look for manual-approval
if manualApproval, exists := on["manual-approval"]; exists {
if str, ok := manualApproval.(string); ok {
manualApprovalLog.Printf("Found manual-approval configuration: %s", str)
return str, nil
}
return "", fmt.Errorf("manual-approval value must be a string")
}
manualApprovalLog.Print("on: section is object format but no manual-approval field found")
return "", nil
default:
return "", fmt.Errorf("invalid on: section format")
Expand All @@ -32,12 +40,21 @@ func (c *Compiler) extractManualApprovalFromOn(frontmatter map[string]any) (stri

// processManualApprovalConfiguration extracts manual-approval configuration from frontmatter
func (c *Compiler) processManualApprovalConfiguration(frontmatter map[string]any, workflowData *WorkflowData) error {
manualApprovalLog.Print("Processing manual-approval configuration")

// Extract manual-approval from the on: section
manualApproval, err := c.extractManualApprovalFromOn(frontmatter)
if err != nil {
manualApprovalLog.Printf("Failed to extract manual-approval: %v", err)
return err
}
workflowData.ManualApproval = manualApproval

if manualApproval != "" {
manualApprovalLog.Printf("Manual approval configured for workflow: %s", manualApproval)
} else {
manualApprovalLog.Print("No manual approval configured for workflow")
}

return nil
}
5 changes: 5 additions & 0 deletions pkg/workflow/secret_masking.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

// extractSecretMaskingConfig extracts secret-masking configuration from frontmatter
func (c *Compiler) extractSecretMaskingConfig(frontmatter map[string]any) *SecretMaskingConfig {
secretMaskingLog.Print("Extracting secret-masking configuration from frontmatter")

if secretMasking, exists := frontmatter["secret-masking"]; exists {
if secretMaskingMap, ok := secretMasking.(map[string]any); ok {
config := &SecretMaskingConfig{}
Expand All @@ -21,18 +23,21 @@ func (c *Compiler) extractSecretMaskingConfig(frontmatter map[string]any) *Secre
}
}
config.Steps = stepsConfig
secretMaskingLog.Printf("Extracted %d secret-masking steps from frontmatter", len(stepsConfig))
}
}

// Return nil if no steps were found
if len(config.Steps) == 0 {
secretMaskingLog.Print("No secret-masking steps found in frontmatter")
return nil
}

return config
}
}

secretMaskingLog.Print("No secret-masking configuration found in frontmatter")
return nil
}

Expand Down
18 changes: 16 additions & 2 deletions pkg/workflow/time_delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import (
"strconv"
"strings"
"time"

"github.com/githubnext/gh-aw/pkg/logger"
)

var timeDeltaLog = logger.New("workflow:time_delta")

// Pre-compiled regexes for time parsing (performance optimization)
var (
timeDeltaPattern = regexp.MustCompile(`(\d+)(mo|w|d|h|m)`)
Expand Down Expand Up @@ -53,12 +57,15 @@ func parseTimeDeltaForStopAfter(deltaStr string) (*TimeDelta, error) {

// parseTimeDeltaWithMinutes parses a relative time delta string with optional minute support
func parseTimeDeltaWithMinutes(deltaStr string, allowMinutes bool) (*TimeDelta, error) {
timeDeltaLog.Printf("Parsing time delta: input=%s, allowMinutes=%v", deltaStr, allowMinutes)

if deltaStr == "" {
return nil, fmt.Errorf("empty time delta")
}

// Must start with '+'
if !strings.HasPrefix(deltaStr, "+") {
timeDeltaLog.Printf("Time delta validation failed: missing '+' prefix")
return nil, fmt.Errorf("time delta must start with '+', got: %s", deltaStr)
}

Expand Down Expand Up @@ -148,6 +155,7 @@ func parseTimeDeltaWithMinutes(deltaStr string, allowMinutes bool) (*TimeDelta,
return nil, fmt.Errorf("time delta too large: %d minutes exceeds maximum of 525600 minutes", delta.Minutes)
}

timeDeltaLog.Printf("Parsed time delta successfully: %s", delta.String())
return delta, nil
}

Expand Down Expand Up @@ -182,6 +190,8 @@ func isRelativeStopTime(stopTime string) bool {

// parseAbsoluteDateTime parses various date-time formats and returns a standardized timestamp
func parseAbsoluteDateTime(dateTimeStr string) (string, error) {
timeDeltaLog.Printf("Parsing absolute date-time: %s", dateTimeStr)

// Try multiple date-time formats in order of preference
formats := []string{
// Standard formats
Expand Down Expand Up @@ -236,7 +246,9 @@ func parseAbsoluteDateTime(dateTimeStr string) (string, error) {
for _, format := range formats {
if parsed, err := time.Parse(format, dateTimeStr); err == nil {
// Successfully parsed, convert to UTC and return in standard format
return parsed.UTC().Format("2006-01-02 15:04:05"), nil
result := parsed.UTC().Format("2006-01-02 15:04:05")
timeDeltaLog.Printf("Successfully parsed date-time using format, result: %s", result)
return result, nil
}
}

Expand All @@ -247,7 +259,9 @@ func parseAbsoluteDateTime(dateTimeStr string) (string, error) {
for _, format := range formats {
if parsed, err := time.Parse(format, normalizedStr); err == nil {
// Successfully parsed, convert to UTC and return in standard format
return parsed.UTC().Format("2006-01-02 15:04:05"), nil
result := parsed.UTC().Format("2006-01-02 15:04:05")
timeDeltaLog.Printf("Successfully parsed date-time using ordinal normalization, result: %s", result)
return result, nil
}
}

Expand Down
14 changes: 13 additions & 1 deletion pkg/workflow/xml_comments.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package workflow

import "strings"
import (
"strings"

"github.com/githubnext/gh-aw/pkg/logger"
)

var xmlCommentsLog = logger.New("workflow:xml_comments")

// removeXMLComments removes XML comments (<!-- -->) from markdown content
// while preserving comments that appear within code blocks
func removeXMLComments(content string) string {
xmlCommentsLog.Printf("Removing XML comments from content: %d lines", len(strings.Split(content, "\n")))

// Track if we're inside a code block to avoid removing comments in code
lines := strings.Split(content, "\n")
var result []string
inCodeBlock := false
var openMarker string
inXMLComment := false
removedComments := 0

for _, line := range lines {
// If we're in a code block, preserve the line as-is (ignore XML comment processing)
Expand All @@ -33,6 +42,7 @@ func removeXMLComments(content string) string {
// If we're in an XML comment, skip this line entirely (including code block markers)
if wasInComment && isInComment {
// In the middle of a comment, skip the line completely
removedComments++
continue
}

Expand All @@ -43,6 +53,7 @@ func removeXMLComments(content string) string {
// Opening a code block
openMarker, _ = extractCodeBlockMarker(trimmedLine)
inCodeBlock = true
xmlCommentsLog.Printf("Detected code block opening with marker: %s", openMarker)
result = append(result, processedLine)
continue
}
Expand All @@ -65,6 +76,7 @@ func removeXMLComments(content string) string {
}
}

xmlCommentsLog.Printf("XML comment removal completed: removed %d comment lines, output %d lines", removedComments, len(result))
return strings.Join(result, "\n")
}

Expand Down