diff --git a/pkg/cli/dispatch.go b/pkg/cli/dispatch.go index 495391dfc21..6c9110f0e83 100644 --- a/pkg/cli/dispatch.go +++ b/pkg/cli/dispatch.go @@ -76,6 +76,7 @@ type fileDownloadFn func(owner, repo, path, ref string) ([]byte, error) // An optional downloader function may be provided as the last argument to override the default // parser.DownloadFileFromGitHub implementation (used in tests to avoid real network calls). func fetchAndSaveRemoteDispatchWorkflows(ctx context.Context, content string, spec *WorkflowSpec, targetDir string, verbose bool, force bool, tracker *FileTracker, downloaders ...fileDownloadFn) error { + remoteWorkflowLog.Printf("Fetching remote dispatch workflows: repo=%s, targetDir=%s, force=%v", spec.RepoSlug, targetDir, force) downloader := fileDownloadFn(parser.DownloadFileFromGitHub) if len(downloaders) > 0 && downloaders[0] != nil { downloader = downloaders[0] @@ -106,6 +107,8 @@ func fetchAndSaveRemoteDispatchWorkflows(ctx context.Context, content string, sp return nil } + remoteWorkflowLog.Printf("Found %d dispatch workflow(s) to fetch from %s@%s", len(workflowNames), spec.RepoSlug, ref) + // workflowBaseDir is the directory of the source workflow in the remote repo // (e.g. ".github/workflows"). Dispatch-workflow names are resolved relative to it. workflowBaseDir := getParentDir(spec.WorkflowPath) @@ -169,6 +172,7 @@ func fetchAndSaveRemoteDispatchWorkflows(ctx context.Context, content string, sp // (the dispatch-workflow validator accepts either .md or .yml files locally). workflowContent, err := downloader(owner, repo, remoteFilePath, ref) if err != nil { + remoteWorkflowLog.Printf(".md fetch failed for dispatch workflow %s, trying .yml fallback", workflowName) // .md not found — try .yml fallback (e.g. plain GitHub Actions workflow) ymlRemotePath := path.Clean(strings.TrimSuffix(remoteFilePath, ".md") + ".yml") ymlLocalPath := filepath.Join(targetDir, filepath.Clean(workflowName+".yml")) @@ -263,6 +267,7 @@ func fetchAndSaveRemoteDispatchWorkflows(ctx context.Context, content string, sp // Parse failures are logged at debug level so they can be investigated when needed. // Source conflicts are reported as warnings (not errors) because the main file is already written. func fetchAndSaveDispatchWorkflowsFromParsedFile(destFile string, spec *WorkflowSpec, targetDir string, verbose bool, force bool, tracker *FileTracker) { + remoteWorkflowLog.Printf("Fetching import-derived dispatch workflows from parsed file: %s, repo=%s", destFile, spec.RepoSlug) if spec.RepoSlug == "" { return } @@ -304,6 +309,8 @@ func fetchAndSaveDispatchWorkflowsFromParsedFile(destFile string, spec *Workflow return } + remoteWorkflowLog.Printf("Processing %d import-derived dispatch workflow(s) (filtered from %d)", len(filtered), len(workflowNames)) + workflowBaseDir := getParentDir(spec.WorkflowPath) absTargetDir, absErr := filepath.Abs(targetDir) diff --git a/pkg/cli/includes.go b/pkg/cli/includes.go index d6301864a5f..ecf01d75f09 100644 --- a/pkg/cli/includes.go +++ b/pkg/cli/includes.go @@ -273,6 +273,7 @@ func fetchFrontmatterImportsRecursive(content, owner, repo, ref, currentBaseDir, // Cycle/duplicate prevention: use the fully-resolved remote path as the key. if seen[remoteFilePath] { + remoteWorkflowLog.Printf("Skipping already-seen import: %s", remoteFilePath) continue } seen[remoteFilePath] = true @@ -331,6 +332,7 @@ func fetchFrontmatterImportsRecursive(content, owner, repo, ref, currentBaseDir, // Download from the source repository importContent, err := parser.DownloadFileFromGitHub(owner, repo, remoteFilePath, ref) if err != nil { + remoteWorkflowLog.Printf("Failed to download import %s from %s/%s@%s: %v", remoteFilePath, owner, repo, ref, err) if verbose { fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to fetch import %s: %v", remoteFilePath, err))) } @@ -487,6 +489,7 @@ func fetchAndSaveRemoteIncludes(content string, spec *WorkflowSpec, targetDir st // verbose is true but do not stop the overall operation. // - Dispatch-workflow and resource errors are fatal and are returned to the caller. func fetchAllRemoteDependencies(ctx context.Context, content string, spec *WorkflowSpec, targetDir string, verbose bool, force bool, tracker *FileTracker) error { + remoteWorkflowLog.Printf("Fetching all remote dependencies: spec=%s, targetDir=%s, force=%v", spec.String(), targetDir, force) // Fetch and save @include directive dependencies (best-effort: errors are not fatal). if err := fetchAndSaveRemoteIncludes(content, spec, targetDir, verbose, force, tracker); err != nil { if verbose { diff --git a/pkg/cli/lint_command.go b/pkg/cli/lint_command.go index 6dde73d5d20..7d5daeac91f 100644 --- a/pkg/cli/lint_command.go +++ b/pkg/cli/lint_command.go @@ -9,9 +9,12 @@ import ( "strings" "github.com/github/gh-aw/pkg/constants" + "github.com/github/gh-aw/pkg/logger" "github.com/spf13/cobra" ) +var lintCommandLog = logger.New("cli:lint_command") + var defaultGhAwActionlintIgnorePatterns = []string{ // gh-aw extends GitHub Actions permissions with copilot-requests. `unknown permission scope "copilot-requests"`, @@ -40,11 +43,16 @@ Examples: includePyflakes, _ := cmd.Flags().GetBool("pyflakes") verbose, _ := cmd.Flags().GetBool("verbose") + lintCommandLog.Printf("Executing lint: dir=%s, shellcheck=%v, pyflakes=%v, args=%d", workflowDir, includeShellcheck, includePyflakes, len(args)) + lockFiles, err := resolveLockFilesForLint(args, workflowDir) if err != nil { + lintCommandLog.Printf("Failed to resolve lock files: %v", err) return err } + lintCommandLog.Printf("Resolved %d lock file(s) for linting", len(lockFiles)) + initActionlintStats() defer displayActionlintSummary() @@ -108,6 +116,7 @@ func expandLintCandidate(candidate string) ([]string, error) { if err != nil { return nil, fmt.Errorf("failed to scan %q for .lock.yml files: %w", candidate, err) } + lintCommandLog.Printf("Expanded directory %s to %d .lock.yml file(s)", candidate, len(lockFiles)) return lockFiles, nil } diff --git a/pkg/cli/logs_run_processor.go b/pkg/cli/logs_run_processor.go index 82dff7e455f..ef398cf5581 100644 --- a/pkg/cli/logs_run_processor.go +++ b/pkg/cli/logs_run_processor.go @@ -110,6 +110,7 @@ func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, out // Try to load cached summary first if summary, ok := loadRunSummary(runOutputDir, verbose); ok { + logsOrchestratorLog.Printf("Cache hit for run %d, using cached summary", run.DatabaseID) // Valid cached summary exists, use it directly result := DownloadResult{ Run: summary.Run, @@ -150,6 +151,7 @@ func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, out runOwner, runRepo, runHost = c.Owner, c.Repo, c.Host } } + logsOrchestratorLog.Printf("Downloading artifacts for run %d: owner=%s, repo=%s", run.DatabaseID, runOwner, runRepo) err := downloadRunArtifacts(ctx, run.DatabaseID, runOutputDir, verbose, runOwner, runRepo, runHost, artifactFilter) result := DownloadResult{ @@ -160,6 +162,7 @@ func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, out if err != nil { // Check if this is a "no artifacts" case if errors.Is(err, ErrNoArtifacts) { + logsOrchestratorLog.Printf("No artifacts available for run %d (conclusion=%s)", run.DatabaseID, run.Conclusion) // For runs with important conclusions (timed_out, failure, cancelled), // still process them even without artifacts to show the failure in reports if isFailureConclusion(run.Conclusion) { @@ -431,6 +434,7 @@ func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, out fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Completed parallel processing: %d successful, %d total", successCount, len(results)))) } + logsOrchestratorLog.Printf("Concurrent download complete: total=%d, results=%d", len(actualRuns), len(results)) return results } diff --git a/pkg/cli/trial_helpers.go b/pkg/cli/trial_helpers.go index f200608e95d..9ee83cd59db 100644 --- a/pkg/cli/trial_helpers.go +++ b/pkg/cli/trial_helpers.go @@ -178,6 +178,7 @@ func executeTrialRun(ctx context.Context, parsedSpecs []*WorkflowSpec, hostRepoS } func triggerWorkflowRun(repoSlug, workflowName string, triggerContext string, verbose bool) (string, error) { + trialLog.Printf("Triggering workflow run: workflow=%s, repo=%s, hasTriggerContext=%v", workflowName, repoSlug, triggerContext != "") if verbose { fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Triggering workflow run for: "+workflowName)) } @@ -271,6 +272,7 @@ func saveTrialResult(filename string, result any, verbose bool) error { // copyTrialResultsToHostRepo copies trial result files to the host repository and commits them func copyTrialResultsToHostRepo(tempDir, dateTimeID string, workflowNames []string, targetRepoSlug string, verbose bool) error { + trialLog.Printf("Copying trial results to host repo: workflows=%d, dateTimeID=%s, targetRepo=%s", len(workflowNames), dateTimeID, targetRepoSlug) if verbose { fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Copying trial results to host repository")) } @@ -340,6 +342,7 @@ func copyTrialResultsToHostRepo(tempDir, dateTimeID string, workflowNames []stri // If no changes, skip commit and push if len(strings.TrimSpace(string(statusOutput))) == 0 { + trialLog.Print("No new trial results to commit, skipping push") if verbose { fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No new trial results to commit")) }