diff --git a/pkg/cli/add_command.go b/pkg/cli/add_command.go index 2b0a118d5b..2f6e2360ed 100644 --- a/pkg/cli/add_command.go +++ b/pkg/cli/add_command.go @@ -32,6 +32,7 @@ Examples: ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/workflows/ci-doctor.md@main ` + string(constants.CLIExtensionPrefix) + ` add https://github.com/githubnext/agentics/blob/main/workflows/ci-doctor.md ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --create-pull-request --force + ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --push # Add and push changes ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/* ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/*@v1.0.0 ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --dir shared # Add to .github/workflows/shared/ @@ -47,6 +48,7 @@ Workflow specifications: The -n flag allows you to specify a custom name for the workflow file (only applies to the first workflow when adding multiple). The --dir flag allows you to specify a subdirectory under .github/workflows/ where the workflow will be added. The --create-pull-request flag (or --pr) automatically creates a pull request with the workflow changes. +The --push flag automatically commits and pushes changes after successful workflow addition. The --force flag overwrites existing workflow files. Note: To create a new workflow from scratch, use the 'new' command instead.`, @@ -59,6 +61,7 @@ Note: To create a new workflow from scratch, use the 'new' command instead.`, createPRFlag, _ := cmd.Flags().GetBool("create-pull-request") prFlagAlias, _ := cmd.Flags().GetBool("pr") prFlag := createPRFlag || prFlagAlias // Support both --create-pull-request and --pr + pushFlag, _ := cmd.Flags().GetBool("push") forceFlag, _ := cmd.Flags().GetBool("force") appendText, _ := cmd.Flags().GetString("append") verbose, _ := cmd.Flags().GetBool("verbose") @@ -73,9 +76,9 @@ Note: To create a new workflow from scratch, use the 'new' command instead.`, // Handle normal mode if prFlag { - return AddWorkflows(workflows, numberFlag, verbose, engineOverride, nameFlag, forceFlag, appendText, true, noGitattributes, workflowDir, noStopAfter, stopAfter) + return AddWorkflows(workflows, numberFlag, verbose, engineOverride, nameFlag, forceFlag, appendText, true, pushFlag, noGitattributes, workflowDir, noStopAfter, stopAfter) } else { - return AddWorkflows(workflows, numberFlag, verbose, engineOverride, nameFlag, forceFlag, appendText, false, noGitattributes, workflowDir, noStopAfter, stopAfter) + return AddWorkflows(workflows, numberFlag, verbose, engineOverride, nameFlag, forceFlag, appendText, false, pushFlag, noGitattributes, workflowDir, noStopAfter, stopAfter) } }, } @@ -97,6 +100,9 @@ Note: To create a new workflow from scratch, use the 'new' command instead.`, cmd.Flags().Bool("pr", false, "Alias for --create-pull-request") _ = cmd.Flags().MarkHidden("pr") // Hide the short alias from help output + // Add push flag to add command + cmd.Flags().Bool("push", false, "Automatically commit and push changes after successful workflow addition") + // Add force flag to add command cmd.Flags().BoolP("force", "f", false, "Overwrite existing workflow files without confirmation") @@ -124,8 +130,8 @@ Note: To create a new workflow from scratch, use the 'new' command instead.`, // AddWorkflows adds one or more workflows from components to .github/workflows // with optional repository installation and PR creation -func AddWorkflows(workflows []string, number int, verbose bool, engineOverride string, name string, force bool, appendText string, createPR bool, noGitattributes bool, workflowDir string, noStopAfter bool, stopAfter string) error { - addLog.Printf("Adding workflows: count=%d, engineOverride=%s, createPR=%v, noGitattributes=%v, workflowDir=%s, noStopAfter=%v, stopAfter=%s", len(workflows), engineOverride, createPR, noGitattributes, workflowDir, noStopAfter, stopAfter) +func AddWorkflows(workflows []string, number int, verbose bool, engineOverride string, name string, force bool, appendText string, createPR bool, push bool, noGitattributes bool, workflowDir string, noStopAfter bool, stopAfter string) error { + addLog.Printf("Adding workflows: count=%d, engineOverride=%s, createPR=%v, push=%v, noGitattributes=%v, workflowDir=%s, noStopAfter=%v, stopAfter=%s", len(workflows), engineOverride, createPR, push, noGitattributes, workflowDir, noStopAfter, stopAfter) if len(workflows) == 0 { return fmt.Errorf("at least one workflow name is required") @@ -143,21 +149,27 @@ func AddWorkflows(workflows []string, number int, verbose bool, engineOverride s return handleRepoOnlySpec(workflows[0], verbose) } - // If creating a PR, check prerequisites - if createPR { - // Check if GitHub CLI is available - if !isGHCLIAvailable() { - return fmt.Errorf("GitHub CLI (gh) is required for PR creation but not available") - } - + // If creating a PR or pushing, check prerequisites + if createPR || push { // Check if we're in a git repository if !isGitRepo() { - return fmt.Errorf("not in a git repository - PR creation requires a git repository") + if createPR { + return fmt.Errorf("not in a git repository - PR creation requires a git repository") + } + return fmt.Errorf("not in a git repository - push requires a git repository") } // Check no other changes are present if err := checkCleanWorkingDirectory(verbose); err != nil { - return fmt.Errorf("working directory is not clean: %w", err) + if createPR { + return fmt.Errorf("working directory is not clean: %w", err) + } + return fmt.Errorf("--push requires a clean working directory: %w", err) + } + + // Check if GitHub CLI is available (only for PR) + if createPR && !isGHCLIAvailable() { + return fmt.Errorf("GitHub CLI (gh) is required for PR creation but not available") } } @@ -243,7 +255,7 @@ func AddWorkflows(workflows []string, number int, verbose bool, engineOverride s // Handle normal workflow addition addLog.Print("Adding workflows normally without PR") - return addWorkflowsNormal(processedWorkflows, number, verbose, engineOverride, name, force, appendText, noGitattributes, hasWildcard, workflowDir, noStopAfter, stopAfter) + return addWorkflowsNormal(processedWorkflows, number, verbose, engineOverride, name, force, appendText, push, noGitattributes, hasWildcard, workflowDir, noStopAfter, stopAfter) } // handleRepoOnlySpec handles the case when user provides only owner/repo without workflow name @@ -398,7 +410,7 @@ func displayAvailableWorkflows(repoSlug, version string, verbose bool) error { } // addWorkflowsNormal handles normal workflow addition without PR creation -func addWorkflowsNormal(workflows []*WorkflowSpec, number int, verbose bool, engineOverride string, name string, force bool, appendText string, noGitattributes bool, fromWildcard bool, workflowDir string, noStopAfter bool, stopAfter string) error { +func addWorkflowsNormal(workflows []*WorkflowSpec, number int, verbose bool, engineOverride string, name string, force bool, appendText string, push bool, noGitattributes bool, fromWildcard bool, workflowDir string, noStopAfter bool, stopAfter string) error { // Create file tracker for all operations tracker, err := NewFileTracker() if err != nil { @@ -448,6 +460,55 @@ func addWorkflowsNormal(workflows []*WorkflowSpec, number int, verbose bool, eng fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Successfully added all %d workflows", len(workflows)))) } + // If --push is enabled, commit and push changes + if push { + addLog.Print("Push enabled - preparing to commit and push changes") + fmt.Fprintln(os.Stderr, "") + + // Check if we're on the default branch + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Checking current branch...")) + if err := checkOnDefaultBranch(verbose); err != nil { + addLog.Printf("Default branch check failed: %v", err) + return fmt.Errorf("cannot push: %w", err) + } + + // Confirm with user (skip in CI) + if err := confirmPushOperation(verbose); err != nil { + addLog.Printf("Push operation not confirmed: %v", err) + return fmt.Errorf("push operation cancelled: %w", err) + } + + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Preparing to commit and push changes...")) + + // Create commit message + var commitMessage string + if len(workflows) == 1 { + commitMessage = fmt.Sprintf("chore: add workflow %s", workflows[0].WorkflowName) + } else { + commitMessage = fmt.Sprintf("chore: add %d workflows", len(workflows)) + } + + // Use the helper function to orchestrate the full workflow + if err := commitAndPushChanges(commitMessage, verbose); err != nil { + // Check if it's the "no changes" case + hasChanges, checkErr := hasChangesToCommit() + if checkErr == nil && !hasChanges { + addLog.Print("No changes to commit") + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No changes to commit")) + } else { + return err + } + } else { + // Print success messages based on whether remote exists + fmt.Fprintln(os.Stderr, "") + if hasRemote() { + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ Changes pushed to remote")) + } else { + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✓ Changes committed locally (no remote configured)")) + } + } + } + return nil } @@ -481,7 +542,7 @@ func addWorkflowsWithPR(workflows []*WorkflowSpec, number int, verbose bool, eng }() // Add workflows using the normal function logic - if err := addWorkflowsNormal(workflows, number, verbose, engineOverride, name, force, appendText, noGitattributes, fromWildcard, workflowDir, noStopAfter, stopAfter); err != nil { + if err := addWorkflowsNormal(workflows, number, verbose, engineOverride, name, force, appendText, false, noGitattributes, fromWildcard, workflowDir, noStopAfter, stopAfter); err != nil { // Rollback on error if rollbackErr := tracker.RollbackAllFiles(verbose); rollbackErr != nil && verbose { fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to rollback files: %v", rollbackErr))) diff --git a/pkg/cli/add_command_test.go b/pkg/cli/add_command_test.go index 65d2895142..c6a6a69277 100644 --- a/pkg/cli/add_command_test.go +++ b/pkg/cli/add_command_test.go @@ -51,6 +51,10 @@ func TestNewAddCommand(t *testing.T) { prFlag := flags.Lookup("pr") assert.NotNil(t, prFlag, "Should have 'pr' flag (alias)") + // Check push flag + pushFlag := flags.Lookup("push") + assert.NotNil(t, pushFlag, "Should have 'push' flag") + // Check force flag forceFlag := flags.Lookup("force") assert.NotNil(t, forceFlag, "Should have 'force' flag") @@ -78,7 +82,7 @@ func TestNewAddCommand(t *testing.T) { } func TestAddWorkflows_EmptyWorkflows(t *testing.T) { - err := AddWorkflows([]string{}, 1, false, "", "", false, "", false, false, "", false, "") + err := AddWorkflows([]string{}, 1, false, "", "", false, "", false, false, false, "", false, "") require.Error(t, err, "Should error when no workflows are provided") assert.Contains(t, err.Error(), "at least one workflow", "Error should mention missing workflow") } diff --git a/pkg/cli/add_current_repo_test.go b/pkg/cli/add_current_repo_test.go index bdd8fbd0ad..a77259fafa 100644 --- a/pkg/cli/add_current_repo_test.go +++ b/pkg/cli/add_current_repo_test.go @@ -78,7 +78,7 @@ func TestAddWorkflowsFromCurrentRepository(t *testing.T) { // Clear cache before each test ClearCurrentRepoSlugCache() - err := AddWorkflows(tt.workflowSpecs, 1, false, "", "", false, "", false, false, "", false, "") + err := AddWorkflows(tt.workflowSpecs, 1, false, "", "", false, "", false, false, false, "", false, "") if tt.expectError { if err == nil { @@ -179,7 +179,7 @@ func TestAddWorkflowsFromCurrentRepositoryMultiple(t *testing.T) { // Clear cache before each test ClearCurrentRepoSlugCache() - err := AddWorkflows(tt.workflowSpecs, 1, false, "", "", false, "", false, false, "", false, "") + err := AddWorkflows(tt.workflowSpecs, 1, false, "", "", false, "", false, false, false, "", false, "") if tt.expectError { if err == nil { @@ -220,7 +220,7 @@ func TestAddWorkflowsFromCurrentRepositoryNotInGitRepo(t *testing.T) { // When not in a git repo, the check should be skipped (can't determine current repo) // The function should proceed and fail for other reasons (e.g., workflow not found) - err = AddWorkflows([]string{"some-owner/some-repo/workflow"}, 1, false, "", "", false, "", false, false, "", false, "") + err = AddWorkflows([]string{"some-owner/some-repo/workflow"}, 1, false, "", "", false, "", false, false, false, "", false, "") // Should NOT get the "cannot add workflows from the current repository" error if err != nil && strings.Contains(err.Error(), "cannot add workflows from the current repository") { diff --git a/pkg/cli/add_gitattributes_test.go b/pkg/cli/add_gitattributes_test.go index daf2e5bf8c..0b2f6f6f20 100644 --- a/pkg/cli/add_gitattributes_test.go +++ b/pkg/cli/add_gitattributes_test.go @@ -82,7 +82,8 @@ This is a test workflow.` os.Remove(".gitattributes") // Call addWorkflowsNormal with noGitattributes=false - err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", false, false, "", false, "") + // Signature: addWorkflowsNormal(workflows, number, verbose, engineOverride, name, force, appendText, push, noGitattributes, fromWildcard, workflowDir, noStopAfter, stopAfter) + err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", false, false, false, "", false, "") if err != nil { // We expect this to fail because we don't have a full workflow setup, // but gitattributes should still be updated before the error @@ -112,7 +113,8 @@ This is a test workflow.` os.Remove(".gitattributes") // Call addWorkflowsNormal with noGitattributes=true - err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", true, false, "", false, "") + // Signature: addWorkflowsNormal(workflows, number, verbose, engineOverride, name, force, appendText, push, noGitattributes, fromWildcard, workflowDir, noStopAfter, stopAfter) + err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", false, true, false, "", false, "") if err != nil { // We expect this to fail because we don't have a full workflow setup t.Logf("Expected error during workflow addition: %v", err) @@ -134,7 +136,8 @@ This is a test workflow.` } // Call addWorkflowsNormal with noGitattributes=true - err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", true, false, "", false, "") + // Signature: addWorkflowsNormal(workflows, number, verbose, engineOverride, name, force, appendText, push, noGitattributes, fromWildcard, workflowDir, noStopAfter, stopAfter) + err := addWorkflowsNormal([]*WorkflowSpec{spec}, 1, false, "", "", false, "", false, true, false, "", false, "") if err != nil { // We expect this to fail because we don't have a full workflow setup t.Logf("Expected error during workflow addition: %v", err) diff --git a/pkg/cli/init.go b/pkg/cli/init.go index 5f60f667b5..5bc2b3749c 100644 --- a/pkg/cli/init.go +++ b/pkg/cli/init.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "math/rand" "os" "path/filepath" "strings" @@ -447,18 +448,32 @@ func attemptSetSecret(secretName, repoSlug string, verbose bool) error { } // InitRepository initializes the repository for agentic workflows -func InitRepository(verbose bool, mcp bool, campaign bool, tokens bool, engine string, codespaceRepos []string, codespaceEnabled bool, completions bool, push bool, rootCmd CommandProvider) error { +func InitRepository(verbose bool, mcp bool, campaign bool, tokens bool, engine string, codespaceRepos []string, codespaceEnabled bool, completions bool, push bool, shouldCreatePR bool, rootCmd CommandProvider) error { initLog.Print("Starting repository initialization for agentic workflows") - // If --push is enabled, ensure git status is clean before starting - if push { - initLog.Print("Checking for clean working directory (--push enabled)") + // If --push or --create-pull-request is enabled, ensure git status is clean before starting + if push || shouldCreatePR { + if shouldCreatePR { + initLog.Print("Checking for clean working directory (--create-pull-request enabled)") + } else { + initLog.Print("Checking for clean working directory (--push enabled)") + } if err := checkCleanWorkingDirectory(verbose); err != nil { initLog.Printf("Git status check failed: %v", err) + if shouldCreatePR { + return fmt.Errorf("--create-pull-request requires a clean working directory: %w", err) + } return fmt.Errorf("--push requires a clean working directory: %w", err) } } + // If creating a PR, check GitHub CLI is available + if shouldCreatePR { + if !isGHCLIAvailable() { + return fmt.Errorf("GitHub CLI (gh) is required for PR creation but not available") + } + } + // Ensure we're in a git repository if !isGitRepo() { initLog.Print("Not in a git repository, initialization failed") @@ -679,8 +694,58 @@ func InitRepository(verbose bool, mcp bool, campaign bool, tokens bool, engine s initLog.Print("Repository initialization completed successfully") - // If --push is enabled, commit and push changes - if push { + // If --create-pull-request is enabled, create branch, commit, push, and create PR + if shouldCreatePR { + initLog.Print("Create PR enabled - preparing to create branch, commit, push, and create PR") + fmt.Fprintln(os.Stderr, "") + + // Get current branch for restoration later + currentBranch, err := getCurrentBranch() + if err != nil { + return fmt.Errorf("failed to get current branch: %w", err) + } + + // Create temporary branch + branchName := fmt.Sprintf("init-agentic-workflows-%d", rand.Intn(9000)+1000) + if err := createAndSwitchBranch(branchName, verbose); err != nil { + return fmt.Errorf("failed to create branch %s: %w", branchName, err) + } + + // Commit changes + commitMessage := "chore: initialize agentic workflows" + if err := commitChanges(commitMessage, verbose); err != nil { + // Switch back to original branch before returning error + _ = switchBranch(currentBranch, verbose) + return fmt.Errorf("failed to commit changes: %w", err) + } + + // Push branch + if err := pushBranch(branchName, verbose); err != nil { + // Switch back to original branch before returning error + _ = switchBranch(currentBranch, verbose) + return fmt.Errorf("failed to push branch %s: %w", branchName, err) + } + + // Create PR + prTitle := "Initialize agentic workflows" + prBody := "This PR initializes the repository for agentic workflows by:\n" + + "- Configuring .gitattributes\n" + + "- Creating GitHub Copilot custom instructions\n" + + "- Setting up workflow prompts and agents" + if err := createPR(branchName, prTitle, prBody, verbose); err != nil { + // Switch back to original branch before returning error + _ = switchBranch(currentBranch, verbose) + return fmt.Errorf("failed to create PR: %w", err) + } + + // Switch back to original branch + if err := switchBranch(currentBranch, verbose); err != nil { + return fmt.Errorf("failed to switch back to branch %s: %w", currentBranch, err) + } + + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Created PR for initialization")) + } else if push { + // If --push is enabled, commit and push changes initLog.Print("Push enabled - preparing to commit and push changes") fmt.Fprintln(os.Stderr, "") diff --git a/pkg/cli/init_command.go b/pkg/cli/init_command.go index 59f6b3ac57..2800f28b7a 100644 --- a/pkg/cli/init_command.go +++ b/pkg/cli/init_command.go @@ -84,7 +84,8 @@ Examples: ` + string(constants.CLIExtensionPrefix) + ` init --codespaces # Configure Codespaces ` + string(constants.CLIExtensionPrefix) + ` init --codespaces repo1,repo2 # Codespaces with additional repos ` + string(constants.CLIExtensionPrefix) + ` init --completions # Install shell completions - ` + string(constants.CLIExtensionPrefix) + ` init --push # Initialize and automatically commit/push`, + ` + string(constants.CLIExtensionPrefix) + ` init --push # Initialize and automatically commit/push + ` + string(constants.CLIExtensionPrefix) + ` init --create-pull-request # Initialize and create a pull request`, RunE: func(cmd *cobra.Command, args []string) error { verbose, _ := cmd.Flags().GetBool("verbose") mcpFlag, _ := cmd.Flags().GetBool("mcp") @@ -96,6 +97,9 @@ Examples: codespaceEnabled := cmd.Flags().Changed("codespaces") completions, _ := cmd.Flags().GetBool("completions") push, _ := cmd.Flags().GetBool("push") + createPRFlag, _ := cmd.Flags().GetBool("create-pull-request") + prFlagAlias, _ := cmd.Flags().GetBool("pr") + createPR := createPRFlag || prFlagAlias // Support both --create-pull-request and --pr // Determine MCP state: default true, unless --no-mcp is specified // --mcp flag is kept for backward compatibility (hidden from help) @@ -123,15 +127,16 @@ Examples: if !cmd.Flags().Changed("mcp") && !cmd.Flags().Changed("no-mcp") && !cmd.Flags().Changed("campaign") && !cmd.Flags().Changed("tokens") && !cmd.Flags().Changed("engine") && !cmd.Flags().Changed("codespaces") && - !cmd.Flags().Changed("completions") && !cmd.Flags().Changed("push") { + !cmd.Flags().Changed("completions") && !cmd.Flags().Changed("push") && + !cmd.Flags().Changed("create-pull-request") && !cmd.Flags().Changed("pr") { // Enter interactive mode initCommandLog.Print("Entering interactive mode") return InitRepositoryInteractive(verbose, cmd.Root()) } - initCommandLog.Printf("Executing init command: verbose=%v, mcp=%v, campaign=%v, tokens=%v, engine=%v, codespaces=%v, codespaceEnabled=%v, completions=%v, push=%v", verbose, mcp, campaign, tokens, engine, codespaceRepos, codespaceEnabled, completions, push) - if err := InitRepository(verbose, mcp, campaign, tokens, engine, codespaceRepos, codespaceEnabled, completions, push, cmd.Root()); err != nil { + initCommandLog.Printf("Executing init command: verbose=%v, mcp=%v, campaign=%v, tokens=%v, engine=%v, codespaces=%v, codespaceEnabled=%v, completions=%v, push=%v, createPR=%v", verbose, mcp, campaign, tokens, engine, codespaceRepos, codespaceEnabled, completions, push, createPR) + if err := InitRepository(verbose, mcp, campaign, tokens, engine, codespaceRepos, codespaceEnabled, completions, push, createPR, cmd.Root()); err != nil { initCommandLog.Printf("Init command failed: %v", err) return err } @@ -150,6 +155,9 @@ Examples: cmd.Flags().Lookup("codespaces").NoOptDefVal = " " cmd.Flags().Bool("completions", false, "Install shell completion for the detected shell (bash, zsh, fish, or PowerShell)") cmd.Flags().Bool("push", false, "Automatically commit and push changes after successful initialization") + cmd.Flags().Bool("create-pull-request", false, "Create a pull request with the initialization changes") + cmd.Flags().Bool("pr", false, "Alias for --create-pull-request") + _ = cmd.Flags().MarkHidden("pr") // Hide the short alias from help output // Hide the deprecated --mcp flag from help (kept for backward compatibility) _ = cmd.Flags().MarkHidden("mcp") diff --git a/pkg/cli/init_command_test.go b/pkg/cli/init_command_test.go index ba89d58fa1..1653a2184c 100644 --- a/pkg/cli/init_command_test.go +++ b/pkg/cli/init_command_test.go @@ -85,6 +85,31 @@ func TestNewInitCommand(t *testing.T) { if codespaceFlag.NoOptDefVal != " " { t.Errorf("Expected codespaces flag NoOptDefVal to be ' ' (space), got %q", codespaceFlag.NoOptDefVal) } + + // Check push flag + pushFlag := cmd.Flags().Lookup("push") + if pushFlag == nil { + t.Error("Expected 'push' flag to be defined") + return + } + + // Check create-pull-request flags + createPRFlag := cmd.Flags().Lookup("create-pull-request") + if createPRFlag == nil { + t.Error("Expected 'create-pull-request' flag to be defined") + return + } + + prFlag := cmd.Flags().Lookup("pr") + if prFlag == nil { + t.Error("Expected 'pr' flag to be defined (alias)") + return + } + + // Verify --pr flag is hidden + if !prFlag.Hidden { + t.Error("Expected 'pr' flag to be hidden") + } } func TestInitCommandHelp(t *testing.T) { @@ -180,9 +205,9 @@ func TestInitRepositoryBasic(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test basic init with MCP enabled by default (mcp=true, noMcp=false behavior) - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) failed: %v", err) } // Verify .gitattributes was created/updated @@ -245,9 +270,9 @@ func TestInitRepositoryWithMCP(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test init with MCP explicitly enabled (same as default) - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with MCP failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with MCP failed: %v", err) } // Verify .vscode/mcp.json was created @@ -288,9 +313,9 @@ func TestInitRepositoryWithNoMCP(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test init with --no-mcp flag (mcp=false) - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with --no-mcp failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with --no-mcp failed: %v", err) } // Verify .vscode/mcp.json was NOT created @@ -336,9 +361,9 @@ func TestInitRepositoryWithMCPBackwardCompatibility(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test init with deprecated --mcp flag for backward compatibility (mcp=true) - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with deprecated --mcp flag failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with deprecated --mcp flag failed: %v", err) } // Verify .vscode/mcp.json was created @@ -379,9 +404,9 @@ func TestInitRepositoryVerbose(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test verbose mode with MCP enabled by default (should not error, just produce more output) - err = InitRepository(true, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(true, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) in verbose mode failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) in verbose mode failed: %v", err) } // Verify basic files were still created @@ -406,12 +431,12 @@ func TestInitRepositoryNotInGitRepo(t *testing.T) { } // Don't initialize git repo - should fail for some operations - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) // The function should handle this gracefully or return an error // Based on the implementation, ensureGitAttributes requires git if err == nil { - t.Log("InitRepository(, false, false, nil) succeeded despite not being in a git repo") + t.Log("InitRepository(, false, false, false, nil) succeeded despite not being in a git repo") } } @@ -440,15 +465,15 @@ func TestInitRepositoryIdempotent(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Run init twice with MCP enabled by default - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("First InitRepository(, false, false, nil) failed: %v", err) + t.Fatalf("First InitRepository(, false, false, false, nil) failed: %v", err) } // Second run should be idempotent - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("Second InitRepository(, false, false, nil) failed: %v", err) + t.Fatalf("Second InitRepository(, false, false, false, nil) failed: %v", err) } // Verify .gitattributes still correct @@ -491,14 +516,14 @@ func TestInitRepositoryWithMCPIdempotent(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Run init with MCP twice - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("First InitRepository(, false, false, nil) with MCP failed: %v", err) + t.Fatalf("First InitRepository(, false, false, false, nil) with MCP failed: %v", err) } - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("Second InitRepository(, false, false, nil) with MCP failed: %v", err) + t.Fatalf("Second InitRepository(, false, false, false, nil) with MCP failed: %v", err) } // Verify files still exist and are correct @@ -538,9 +563,9 @@ func TestInitRepositoryCreatesDirectories(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Run init with MCP - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) failed: %v", err) } // Verify directory structure @@ -606,7 +631,7 @@ func TestInitRepositoryErrorHandling(t *testing.T) { } // Test init without git repo (with MCP enabled by default) - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) // Should handle error gracefully or return error // The actual behavior depends on implementation @@ -649,9 +674,9 @@ func TestInitRepositoryWithExistingFiles(t *testing.T) { } // Run init with MCP enabled by default - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) failed: %v", err) } // Verify existing content is preserved and new entry is added @@ -699,9 +724,9 @@ func TestInitRepositoryWithCodespace(t *testing.T) { // Test init with --codespaces flag (with MCP enabled by default and additional repos) additionalRepos := []string{"org/repo1", "owner/repo2"} - err = InitRepository(false, true, false, false, "", additionalRepos, true, false, false, nil) + err = InitRepository(false, true, false, false, "", additionalRepos, true, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with codespaces failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with codespaces failed: %v", err) } // Verify .devcontainer/devcontainer.json was created at default location @@ -764,9 +789,9 @@ func TestInitCommandWithCodespacesNoArgs(t *testing.T) { exec.Command("git", "config", "user.email", "test@example.com").Run() // Test init with --codespaces flag (no additional repos, MCP enabled by default) - err = InitRepository(false, true, false, false, "", []string{}, true, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, true, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with codespaces (no args) failed: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with codespaces (no args) failed: %v", err) } // Verify .devcontainer/devcontainer.json was created at default location diff --git a/pkg/cli/init_mcp_test.go b/pkg/cli/init_mcp_test.go index 36d621c052..07f70f538c 100644 --- a/pkg/cli/init_mcp_test.go +++ b/pkg/cli/init_mcp_test.go @@ -41,9 +41,9 @@ func TestInitRepository_WithMCP(t *testing.T) { } // Call the function with MCP flag (no campaign agent) - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with MCP returned error: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with MCP returned error: %v", err) } // Verify standard files were created @@ -134,15 +134,15 @@ func TestInitRepository_MCP_Idempotent(t *testing.T) { } // Call the function first time with MCP - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with MCP returned error on first call: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with MCP returned error on first call: %v", err) } // Call the function second time with MCP - err = InitRepository(false, true, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, true, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) with MCP returned error on second call: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) with MCP returned error on second call: %v", err) } // Verify files still exist diff --git a/pkg/cli/init_test.go b/pkg/cli/init_test.go index b8558c809a..6117a1e08c 100644 --- a/pkg/cli/init_test.go +++ b/pkg/cli/init_test.go @@ -54,18 +54,18 @@ func TestInitRepository(t *testing.T) { } // Call the function (no MCP or campaign) - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, nil) // Check error expectation if tt.wantError { if err == nil { - t.Errorf("InitRepository(, false, false, nil) expected error, got nil") + t.Errorf("InitRepository(, false, false, false, nil) expected error, got nil") } return } if err != nil { - t.Fatalf("InitRepository(, false, false, nil) returned unexpected error: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) returned unexpected error: %v", err) } // Verify .gitattributes was created @@ -161,15 +161,15 @@ func TestInitRepository_Idempotent(t *testing.T) { } // Call the function first time - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) returned error on first call: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) returned error on first call: %v", err) } // Call the function second time - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) returned error on second call: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) returned error on second call: %v", err) } // Verify files still exist and are correct @@ -233,9 +233,9 @@ func TestInitRepository_Verbose(t *testing.T) { } // Call the function with verbose=true (should not error) - err = InitRepository(true, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(true, false, false, false, "", []string{}, false, false, false, false, nil) if err != nil { - t.Fatalf("InitRepository(, false, false, nil) returned error with verbose=true: %v", err) + t.Fatalf("InitRepository(, false, false, false, nil) returned error with verbose=true: %v", err) } // Verify files were created diff --git a/pkg/cli/interfaces_test.go b/pkg/cli/interfaces_test.go index cc8b835f08..5f3788deb1 100644 --- a/pkg/cli/interfaces_test.go +++ b/pkg/cli/interfaces_test.go @@ -65,7 +65,7 @@ func TestInitRepository_WithNilRootCmd(t *testing.T) { require.NoError(t, err, "Failed to init git repo") // InitRepository with nil rootCmd and completions disabled should succeed - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, nil) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, nil) require.NoError(t, err, "InitRepository with nil rootCmd should succeed when completions are disabled") } @@ -94,7 +94,7 @@ func TestInitRepository_WithRootCmd(t *testing.T) { } // InitRepository with real rootCmd should succeed - err = InitRepository(false, false, false, false, "", []string{}, false, false, false, rootCmd) + err = InitRepository(false, false, false, false, "", []string{}, false, false, false, false, rootCmd) require.NoError(t, err, "InitRepository with rootCmd should succeed") } diff --git a/pkg/cli/trial_repository.go b/pkg/cli/trial_repository.go index 76152bee72..3c2c73eea8 100644 --- a/pkg/cli/trial_repository.go +++ b/pkg/cli/trial_repository.go @@ -202,7 +202,7 @@ func installWorkflowInTrialMode(tempDir string, parsedSpec *WorkflowSpec, logica } // Add the workflow from the installed package - if err := AddWorkflows([]string{parsedSpec.String()}, 1, verbose, "", "", true, appendText, false, false, "", false, ""); err != nil { + if err := AddWorkflows([]string{parsedSpec.String()}, 1, verbose, "", "", true, appendText, false, false, false, "", false, ""); err != nil { return fmt.Errorf("failed to add workflow: %w", err) } }