From 3af4467a345f838b181ca2faba5fc8ec3f7c5876 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:08:07 +0000 Subject: [PATCH 1/4] Initial plan From 359b9aa4f6efc0dde3acb786012d96b5241ce35e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:18:24 +0000 Subject: [PATCH 2/4] Replace local context.Background() with context propagation This enables proper cancellation and concurrency support by passing context from the command level through the call chain rather than creating new background contexts locally. Changes: - Update CreateWorkflowInteractively to accept context parameter - Update compileWorkflow method to accept and use context - Update recompileWorkflow to accept context parameter - Update collectWorkflowFiles to accept and propagate context - Update installWorkflowInTrialMode to accept context parameter - Update RunWorkflowTrials to accept context parameter - Update cmd.Context() calls in command handlers - Remove local context.Background() calls in add_command.go, interactive.go, run_push.go, and trial_repository.go Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- cmd/gh-aw/main.go | 2 +- pkg/cli/add_command.go | 4 +--- pkg/cli/interactive.go | 8 ++++---- pkg/cli/run_push.go | 8 +++----- pkg/cli/run_workflow_execution.go | 2 +- pkg/cli/trial_command.go | 7 ++++--- pkg/cli/trial_repository.go | 4 ++-- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go index 794cbe619d..e8576e3307 100644 --- a/cmd/gh-aw/main.go +++ b/cmd/gh-aw/main.go @@ -97,7 +97,7 @@ Examples: workflowName = args[0] } - return cli.CreateWorkflowInteractively(workflowName, verbose, forceFlag) + return cli.CreateWorkflowInteractively(cmd.Context(), workflowName, verbose, forceFlag) } // Template mode with workflow name diff --git a/pkg/cli/add_command.go b/pkg/cli/add_command.go index 63931725d9..f9a320deb4 100644 --- a/pkg/cli/add_command.go +++ b/pkg/cli/add_command.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "os" "path/filepath" @@ -113,8 +112,7 @@ Note: To create a new workflow from scratch, use the 'new' command instead.`, if useInteractive { addLog.Print("Using interactive mode") - ctx := context.Background() - return RunAddInteractive(ctx, workflows, verbose, engineOverride, noGitattributes, workflowDir, noStopAfter, stopAfter) + return RunAddInteractive(cmd.Context(), workflows, verbose, engineOverride, noGitattributes, workflowDir, noStopAfter, stopAfter) } // Handle normal (non-interactive) mode diff --git a/pkg/cli/interactive.go b/pkg/cli/interactive.go index 77d882042c..13a3fb75e1 100644 --- a/pkg/cli/interactive.go +++ b/pkg/cli/interactive.go @@ -43,7 +43,7 @@ type InteractiveWorkflowBuilder struct { } // CreateWorkflowInteractively prompts the user to build a workflow interactively -func CreateWorkflowInteractively(workflowName string, verbose bool, force bool) error { +func CreateWorkflowInteractively(ctx context.Context, workflowName string, verbose bool, force bool) error { interactiveLog.Printf("Starting interactive workflow creation: workflowName=%s, force=%v", workflowName, force) // Assert this function is not running in automated unit tests @@ -77,7 +77,7 @@ func CreateWorkflowInteractively(workflowName string, verbose bool, force bool) } // Compile the workflow - if err := builder.compileWorkflow(verbose); err != nil { + if err := builder.compileWorkflow(ctx, verbose); err != nil { return fmt.Errorf("failed to compile workflow: %w", err) } @@ -472,7 +472,7 @@ func (b *InteractiveWorkflowBuilder) describeTrigger() string { } // compileWorkflow automatically compiles the generated workflow -func (b *InteractiveWorkflowBuilder) compileWorkflow(verbose bool) error { +func (b *InteractiveWorkflowBuilder) compileWorkflow(ctx context.Context, verbose bool) error { interactiveLog.Printf("Starting workflow compilation: name=%s, verbose=%v", b.WorkflowName, verbose) // Create spinner for compilation progress @@ -494,7 +494,7 @@ func (b *InteractiveWorkflowBuilder) compileWorkflow(verbose bool) error { TrialLogicalRepoSlug: "", } - _, err := CompileWorkflows(context.Background(), config) + _, err := CompileWorkflows(ctx, config) if err != nil { spinner.Stop() diff --git a/pkg/cli/run_push.go b/pkg/cli/run_push.go index 755ab2861d..e964586cd4 100644 --- a/pkg/cli/run_push.go +++ b/pkg/cli/run_push.go @@ -22,7 +22,7 @@ var runPushLog = logger.New("cli:run_push") // and the transitive closure of all imported files. // Note: This function always recompiles the workflow to ensure the lock file is up-to-date, // regardless of the frontmatter hash status. -func collectWorkflowFiles(workflowPath string, verbose bool) ([]string, error) { +func collectWorkflowFiles(ctx context.Context, workflowPath string, verbose bool) ([]string, error) { runPushLog.Printf("Collecting files for workflow: %s", workflowPath) files := make(map[string]bool) // Use map to avoid duplicates @@ -78,7 +78,7 @@ func collectWorkflowFiles(workflowPath string, verbose bool) ([]string, error) { // Always recompile (hash check is for observability only) runPushLog.Printf("Always recompiling workflow: %s", absWorkflowPath) - if err := recompileWorkflow(absWorkflowPath, verbose); err != nil { + if err := recompileWorkflow(ctx, absWorkflowPath, verbose); err != nil { runPushLog.Printf("Failed to recompile workflow: %v", err) return nil, fmt.Errorf("failed to recompile workflow: %w", err) } @@ -119,7 +119,7 @@ func collectWorkflowFiles(workflowPath string, verbose bool) ([]string, error) { } // recompileWorkflow compiles a workflow using CompileWorkflows -func recompileWorkflow(workflowPath string, verbose bool) error { +func recompileWorkflow(ctx context.Context, workflowPath string, verbose bool) error { runPushLog.Printf("Recompiling workflow: %s", workflowPath) config := CompileConfig{ @@ -139,8 +139,6 @@ func recompileWorkflow(workflowPath string, verbose bool) error { runPushLog.Printf("Compilation config: Validate=%v, NoEmit=%v", config.Validate, config.NoEmit) - // Use background context for compilation - ctx := context.Background() runPushLog.Printf("Starting compilation with CompileWorkflows") if _, err := CompileWorkflows(ctx, config); err != nil { runPushLog.Printf("Compilation failed: %v", err) diff --git a/pkg/cli/run_workflow_execution.go b/pkg/cli/run_workflow_execution.go index 9fa8062bc6..7a0d78deba 100644 --- a/pkg/cli/run_workflow_execution.go +++ b/pkg/cli/run_workflow_execution.go @@ -248,7 +248,7 @@ func RunWorkflowOnGitHub(ctx context.Context, workflowIdOrName string, enable bo // Collect the workflow .md file, .lock.yml file, and transitive imports workflowMarkdownPath := stringutil.LockFileToMarkdown(lockFilePath) - files, err := collectWorkflowFiles(workflowMarkdownPath, verbose) + files, err := collectWorkflowFiles(ctx, workflowMarkdownPath, verbose) if err != nil { return fmt.Errorf("failed to collect workflow files: %w", err) } diff --git a/pkg/cli/trial_command.go b/pkg/cli/trial_command.go index e86819c3ef..b975df41ae 100644 --- a/pkg/cli/trial_command.go +++ b/pkg/cli/trial_command.go @@ -1,6 +1,7 @@ package cli import ( + "context" "encoding/json" "fmt" "os" @@ -156,7 +157,7 @@ Trial results are saved both locally (in trials/ directory) and in the host repo Verbose: verbose, } - if err := RunWorkflowTrials(workflowSpecs, opts); err != nil { + if err := RunWorkflowTrials(cmd.Context(), workflowSpecs, opts); err != nil { return err } return nil @@ -193,7 +194,7 @@ Trial results are saved both locally (in trials/ directory) and in the host repo } // RunWorkflowTrials executes the main logic for trialing one or more workflows -func RunWorkflowTrials(workflowSpecs []string, opts TrialOptions) error { +func RunWorkflowTrials(ctx context.Context, workflowSpecs []string, opts TrialOptions) error { trialLog.Printf("Starting trial execution: specs=%v, logicalRepo=%s, cloneRepo=%s, hostRepo=%s, repeat=%d", workflowSpecs, opts.Repos.LogicalRepo, opts.Repos.CloneRepo, opts.Repos.HostRepo, opts.RepeatCount) // Parse all workflow specifications @@ -424,7 +425,7 @@ func RunWorkflowTrials(workflowSpecs []string, opts TrialOptions) error { fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("=== Running trial for workflow: %s ===", parsedSpec.WorkflowName))) // Install workflow with trial mode compilation - if err := installWorkflowInTrialMode(tempDir, parsedSpec, logicalRepoSlug, cloneRepoSlug, hostRepoSlug, secretTracker, opts.EngineOverride, opts.AppendText, opts.PushSecrets, directTrialMode, opts.Verbose); err != nil { + if err := installWorkflowInTrialMode(ctx, tempDir, parsedSpec, logicalRepoSlug, cloneRepoSlug, hostRepoSlug, secretTracker, opts.EngineOverride, opts.AppendText, opts.PushSecrets, directTrialMode, opts.Verbose); err != nil { return fmt.Errorf("failed to install workflow '%s' in trial mode: %w", parsedSpec.WorkflowName, err) } diff --git a/pkg/cli/trial_repository.go b/pkg/cli/trial_repository.go index b9bde84610..50bb32feaf 100644 --- a/pkg/cli/trial_repository.go +++ b/pkg/cli/trial_repository.go @@ -163,7 +163,7 @@ func cloneTrialHostRepository(repoSlug string, verbose bool) (string, error) { } // installWorkflowInTrialMode installs a workflow in trial mode using a parsed spec -func installWorkflowInTrialMode(tempDir string, parsedSpec *WorkflowSpec, logicalRepoSlug, cloneRepoSlug, hostRepoSlug string, secretTracker *TrialSecretTracker, engineOverride string, appendText string, pushSecrets bool, directTrialMode bool, verbose bool) error { +func installWorkflowInTrialMode(ctx context.Context, tempDir string, parsedSpec *WorkflowSpec, logicalRepoSlug, cloneRepoSlug, hostRepoSlug string, secretTracker *TrialSecretTracker, engineOverride string, appendText string, pushSecrets bool, directTrialMode bool, verbose bool) error { trialRepoLog.Printf("Installing workflow in trial mode: workflow=%s, hostRepo=%s, directMode=%v", parsedSpec.WorkflowName, hostRepoSlug, directTrialMode) // Change to temp directory @@ -226,7 +226,7 @@ func installWorkflowInTrialMode(tempDir string, parsedSpec *WorkflowSpec, logica TrialMode: !directTrialMode && (cloneRepoSlug == ""), // Enable trial mode in compiler unless in direct mode or clone-repo mode TrialLogicalRepoSlug: logicalRepoSlug, } - workflowDataList, err := CompileWorkflows(context.Background(), config) + workflowDataList, err := CompileWorkflows(ctx, config) if err != nil { return fmt.Errorf("failed to compile workflow: %w", err) } From 11acf364feae83a6c2e0a786505845ec9e0c622b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:20:27 +0000 Subject: [PATCH 3/4] Update tests to pass context parameter Update test files to pass context.Background() to functions that now require a context parameter. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/interactive_test.go | 9 +++++---- pkg/cli/run_push_test.go | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pkg/cli/interactive_test.go b/pkg/cli/interactive_test.go index 7abca5b276..287c090a67 100644 --- a/pkg/cli/interactive_test.go +++ b/pkg/cli/interactive_test.go @@ -3,6 +3,7 @@ package cli import ( + "context" "os" "strings" "testing" @@ -420,7 +421,7 @@ func TestCreateWorkflowInteractively_InAutomatedEnvironment(t *testing.T) { }) // Test should fail in automated environment - err := CreateWorkflowInteractively("test-workflow", false, false) + err := CreateWorkflowInteractively(context.Background(), "test-workflow", false, false) if err == nil { t.Error("Expected error in automated environment, got nil") } @@ -455,8 +456,8 @@ func TestCreateWorkflowInteractively_WithForceFlag(t *testing.T) { }) // Both with and without force should fail in CI - err1 := CreateWorkflowInteractively("test-workflow", false, false) - err2 := CreateWorkflowInteractively("test-workflow", false, true) + err1 := CreateWorkflowInteractively(context.Background(), "test-workflow", false, false) + err2 := CreateWorkflowInteractively(context.Background(), "test-workflow", false, true) if err1 == nil || err2 == nil { t.Error("Expected errors in CI environment") @@ -479,7 +480,7 @@ func TestInteractiveWorkflowBuilder_compileWorkflow_SpinnerIntegration(t *testin // Test with invalid workflow (should handle error correctly) // This will fail compilation but should not panic - err := builder.compileWorkflow(false) + err := builder.compileWorkflow(context.Background(), false) // We expect an error since the workflow doesn't exist if err == nil { diff --git a/pkg/cli/run_push_test.go b/pkg/cli/run_push_test.go index f5f258d2ea..79d28d9db6 100644 --- a/pkg/cli/run_push_test.go +++ b/pkg/cli/run_push_test.go @@ -3,6 +3,7 @@ package cli import ( + "context" "fmt" "os" "os/exec" @@ -40,7 +41,7 @@ on: workflow_dispatch require.NoError(t, err) // Test collecting files - files, err := collectWorkflowFiles(workflowPath, false) + files, err := collectWorkflowFiles(context.Background(), workflowPath, false) require.NoError(t, err) assert.Len(t, files, 2, "Should collect workflow .md and .lock.yml files") @@ -88,7 +89,7 @@ on: workflow_dispatch require.NoError(t, err) // Test collecting files - files, err := collectWorkflowFiles(workflowPath, false) + files, err := collectWorkflowFiles(context.Background(), workflowPath, false) require.NoError(t, err) assert.Len(t, files, 3, "Should collect workflow, lock, and imported files") @@ -149,7 +150,7 @@ on: workflow_dispatch require.NoError(t, err) // Test collecting files - files, err := collectWorkflowFiles(workflowPath, false) + files, err := collectWorkflowFiles(context.Background(), workflowPath, false) require.NoError(t, err) assert.Len(t, files, 4, "Should collect workflow, lock, and all transitive imports") @@ -483,7 +484,7 @@ jobs: time.Sleep(100 * time.Millisecond) // Collect workflow files (which should always trigger recompilation) - files, err := collectWorkflowFiles(workflowPath, false) + files, err := collectWorkflowFiles(context.Background(), workflowPath, false) require.NoError(t, err) assert.Len(t, files, 2, "Should collect workflow .md and .lock.yml files") From bd434fa1021bca66b2faa4d355ccd60332b25ac5 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 07:47:03 -0800 Subject: [PATCH 4/4] Fix integration test context parameter after collectWorkflowFiles signature change (#13746) --- pkg/cli/run_push_integration_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cli/run_push_integration_test.go b/pkg/cli/run_push_integration_test.go index 819a6d4a45..7e148f3ec9 100644 --- a/pkg/cli/run_push_integration_test.go +++ b/pkg/cli/run_push_integration_test.go @@ -3,6 +3,7 @@ package cli import ( + "context" "os" "path/filepath" "testing" @@ -33,7 +34,7 @@ This is a test workflow without a lock file. require.NoError(t, err) // Test collecting files - should now compile the workflow and create lock file - files, err := collectWorkflowFiles(workflowPath, false) + files, err := collectWorkflowFiles(context.Background(), workflowPath, false) require.NoError(t, err) assert.Len(t, files, 2, "Should collect workflow .md file and auto-generate lock file")