diff --git a/pkg/cli/validators.go b/pkg/cli/validators.go index 9e24f75db7..8363269f53 100644 --- a/pkg/cli/validators.go +++ b/pkg/cli/validators.go @@ -4,20 +4,28 @@ import ( "errors" "regexp" "strings" + + "github.com/githubnext/gh-aw/pkg/logger" ) +var validatorsLog = logger.New("cli:validators") + // workflowNameRegex validates workflow names contain only alphanumeric characters, hyphens, and underscores var workflowNameRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) // ValidateWorkflowName checks if the provided workflow name is valid. // It ensures the name is not empty and contains only alphanumeric characters, hyphens, and underscores. func ValidateWorkflowName(s string) error { + validatorsLog.Printf("Validating workflow name: %s", s) if s == "" { + validatorsLog.Print("Workflow name validation failed: empty name") return errors.New("workflow name cannot be empty") } if !workflowNameRegex.MatchString(s) { + validatorsLog.Printf("Workflow name validation failed: invalid characters in %s", s) return errors.New("workflow name must contain only alphanumeric characters, hyphens, and underscores") } + validatorsLog.Printf("Workflow name validated successfully: %s", s) return nil } @@ -25,12 +33,16 @@ func ValidateWorkflowName(s string) error { // It ensures the intent has meaningful content with at least 20 characters // and is not just whitespace. func ValidateWorkflowIntent(s string) error { + validatorsLog.Printf("Validating workflow intent: length=%d", len(s)) trimmed := strings.TrimSpace(s) if len(trimmed) == 0 { + validatorsLog.Print("Workflow intent validation failed: empty content") return errors.New("workflow instructions cannot be empty") } if len(trimmed) < 20 { + validatorsLog.Printf("Workflow intent validation failed: too short (%d chars)", len(trimmed)) return errors.New("please provide at least 20 characters of instructions") } + validatorsLog.Printf("Workflow intent validated successfully: %d chars", len(trimmed)) return nil } diff --git a/pkg/gitutil/gitutil.go b/pkg/gitutil/gitutil.go index 1224f321cd..4536b1e3f2 100644 --- a/pkg/gitutil/gitutil.go +++ b/pkg/gitutil/gitutil.go @@ -1,18 +1,29 @@ package gitutil -import "strings" +import ( + "strings" + + "github.com/githubnext/gh-aw/pkg/logger" +) + +var log = logger.New("gitutil:gitutil") // IsAuthError checks if an error message indicates an authentication issue. // This is used to detect when GitHub API calls fail due to missing or invalid credentials. func IsAuthError(errMsg string) bool { + log.Printf("Checking if error is auth-related: %s", errMsg) lowerMsg := strings.ToLower(errMsg) - return strings.Contains(lowerMsg, "gh_token") || + isAuth := strings.Contains(lowerMsg, "gh_token") || strings.Contains(lowerMsg, "github_token") || strings.Contains(lowerMsg, "authentication") || strings.Contains(lowerMsg, "not logged into") || strings.Contains(lowerMsg, "unauthorized") || strings.Contains(lowerMsg, "forbidden") || strings.Contains(lowerMsg, "permission denied") + if isAuth { + log.Print("Detected authentication error") + } + return isAuth } // IsHexString checks if a string contains only hexadecimal characters. diff --git a/pkg/repoutil/repoutil.go b/pkg/repoutil/repoutil.go index a6e886c5f6..fd67f61eba 100644 --- a/pkg/repoutil/repoutil.go +++ b/pkg/repoutil/repoutil.go @@ -4,33 +4,44 @@ package repoutil import ( "fmt" "strings" + + "github.com/githubnext/gh-aw/pkg/logger" ) +var log = logger.New("repoutil:repoutil") + // SplitRepoSlug splits a repository slug (owner/repo) into owner and repo parts. // Returns an error if the slug format is invalid. func SplitRepoSlug(slug string) (owner, repo string, err error) { + log.Printf("Splitting repo slug: %s", slug) parts := strings.Split(slug, "/") if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + log.Printf("Invalid repo slug format: %s", slug) return "", "", fmt.Errorf("invalid repo format: %s", slug) } + log.Printf("Split result: owner=%s, repo=%s", parts[0], parts[1]) return parts[0], parts[1], nil } // ParseGitHubURL extracts the owner and repo from a GitHub URL. // Handles both SSH (git@github.com:owner/repo.git) and HTTPS (https://github.com/owner/repo.git) formats. func ParseGitHubURL(url string) (owner, repo string, err error) { + log.Printf("Parsing GitHub URL: %s", url) var repoPath string // SSH format: git@github.com:owner/repo.git if strings.HasPrefix(url, "git@github.com:") { repoPath = strings.TrimPrefix(url, "git@github.com:") + log.Printf("Detected SSH format, extracted path: %s", repoPath) } else if strings.Contains(url, "github.com/") { // HTTPS format: https://github.com/owner/repo.git parts := strings.Split(url, "github.com/") if len(parts) >= 2 { repoPath = parts[1] + log.Printf("Detected HTTPS format, extracted path: %s", repoPath) } } else { + log.Printf("URL does not match known GitHub formats: %s", url) return "", "", fmt.Errorf("URL does not appear to be a GitHub repository: %s", url) } diff --git a/pkg/workflow/github_tool_to_toolset.go b/pkg/workflow/github_tool_to_toolset.go index 6664749b05..fefe2dbfa7 100644 --- a/pkg/workflow/github_tool_to_toolset.go +++ b/pkg/workflow/github_tool_to_toolset.go @@ -3,8 +3,12 @@ package workflow import ( _ "embed" "encoding/json" + + "github.com/githubnext/gh-aw/pkg/logger" ) +var githubToolToToolsetLog = logger.New("workflow:github_tool_to_toolset") + //go:embed data/github_tool_to_toolset.json var githubToolToToolsetJSON []byte @@ -23,7 +27,10 @@ func init() { // ValidateGitHubToolsAgainstToolsets validates that all allowed GitHub tools have their // corresponding toolsets enabled in the configuration func ValidateGitHubToolsAgainstToolsets(allowedTools []string, enabledToolsets []string) error { + githubToolToToolsetLog.Printf("Validating GitHub tools against toolsets: allowed_tools=%d, enabled_toolsets=%d", len(allowedTools), len(enabledToolsets)) + if len(allowedTools) == 0 { + githubToolToToolsetLog.Print("No tools to validate, skipping") // No specific tools restricted, validation not needed return nil } @@ -33,6 +40,7 @@ func ValidateGitHubToolsAgainstToolsets(allowedTools []string, enabledToolsets [ for _, toolset := range enabledToolsets { enabledSet[toolset] = true } + githubToolToToolsetLog.Printf("Enabled toolsets: %v", enabledToolsets) // Track missing toolsets and which tools need them missingToolsets := make(map[string][]string) // toolset -> list of tools that need it @@ -40,19 +48,23 @@ func ValidateGitHubToolsAgainstToolsets(allowedTools []string, enabledToolsets [ for _, tool := range allowedTools { requiredToolset, exists := GitHubToolToToolsetMap[tool] if !exists { + githubToolToToolsetLog.Printf("Tool %s not found in mapping, skipping validation", tool) // Tool not in our mapping - this could be a new tool or a typo // We'll skip validation for unknown tools to avoid false positives continue } if !enabledSet[requiredToolset] { + githubToolToToolsetLog.Printf("Tool %s requires missing toolset: %s", tool, requiredToolset) missingToolsets[requiredToolset] = append(missingToolsets[requiredToolset], tool) } } if len(missingToolsets) > 0 { + githubToolToToolsetLog.Printf("Validation failed: missing %d toolsets", len(missingToolsets)) return NewGitHubToolsetValidationError(missingToolsets) } + githubToolToToolsetLog.Print("Validation successful: all tools have required toolsets") return nil } diff --git a/pkg/workflow/prompts.go b/pkg/workflow/prompts.go index ed02fae95e..82e3732f7d 100644 --- a/pkg/workflow/prompts.go +++ b/pkg/workflow/prompts.go @@ -21,9 +21,12 @@ import ( // hasPlaywrightTool checks if the playwright tool is enabled in the tools configuration func hasPlaywrightTool(parsedTools *Tools) bool { if parsedTools == nil { + log.Print("Checking for Playwright tool: no parsed tools provided") return false } - return parsedTools.Playwright != nil + hasPlaywright := parsedTools.Playwright != nil + log.Printf("Playwright tool enabled: %v", hasPlaywright) + return hasPlaywright } // ============================================================================ @@ -32,12 +35,16 @@ func hasPlaywrightTool(parsedTools *Tools) bool { // hasCommentRelatedTriggers checks if the workflow has any comment-related event triggers func (c *Compiler) hasCommentRelatedTriggers(data *WorkflowData) bool { + log.Printf("Checking for comment-related triggers: command_count=%d, on=%s", len(data.Command), data.On) + // Check for command trigger (which expands to comment events) if len(data.Command) > 0 { + log.Print("Found command trigger, enabling comment-related features") return true } if data.On == "" { + log.Print("No 'on' trigger defined") return false } @@ -45,9 +52,11 @@ func (c *Compiler) hasCommentRelatedTriggers(data *WorkflowData) bool { commentEvents := []string{"issue_comment", "pull_request_review_comment", "pull_request_review"} for _, event := range commentEvents { if strings.Contains(data.On, event) { + log.Printf("Found comment-related event trigger: %s", event) return true } } + log.Print("No comment-related triggers found") return false }