diff --git a/cmd/molecule/molecule_test.go b/cmd/molecule/molecule_test.go index da9811b..8930aba 100644 --- a/cmd/molecule/molecule_test.go +++ b/cmd/molecule/molecule_test.go @@ -796,6 +796,47 @@ func TestCLI_Init_AlreadyExists(t *testing.T) { } } +func TestCLI_Init_Force(t *testing.T) { + exe := mol(t) + dir := t.TempDir() + // pre-create molecule.yaml + existing := "# old config" + os.WriteFile(filepath.Join(dir, "molecule.yaml"), []byte(existing), 0o644) + cmd := exec.Command(exe, "init", "--force") + cmd.Dir = dir + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + if err != nil { + t.Fatalf("molecule init --force: %v\nstderr: %s", err, stderr.String()) + } + out := stdout.String() + if !strings.Contains(out, "Replaced") { + t.Errorf("expected 'Replaced' in output, got: %s", out) + } +} + +func TestCLI_Init_Force_Overwrites(t *testing.T) { + exe := mol(t) + dir := t.TempDir() + // pre-create molecule.yaml + os.WriteFile(filepath.Join(dir, "molecule.yaml"), []byte("old content"), 0o644) + cmd := exec.Command(exe, "init", "--force") + cmd.Dir = dir + err := cmd.Run() + if err != nil { + t.Fatalf("molecule init --force: %v", err) + } + data, _ := os.ReadFile(filepath.Join(dir, "molecule.yaml")) + if strings.Contains(string(data), "old content") { + t.Errorf("molecule.yaml was not overwritten") + } + if !strings.Contains(string(data), "molecule CLI") { + t.Errorf("molecule.yaml should have new scaffold content") + } +} + func TestCLI_Completion_Help(t *testing.T) { exe := mol(t) root := repoRoot() diff --git a/internal/cmd/init.go b/internal/cmd/init.go index 758d4c2..629f9c4 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -12,6 +12,10 @@ import ( // molecule init — bootstrap workspace setup // --------------------------------------------------------------------------- +var ( + initForce bool +) + var initCmd = &cobra.Command{ Use: "init", Short: "Bootstrap workspace and scaffold a molecule.yaml config file", @@ -27,10 +31,41 @@ After init, run 'molecule --config molecule.yaml workspace list' to verify your RunE: runInit, } +func init() { + initCmd.Flags().BoolVar(&initForce, "force", false, "Replace existing molecule.yaml") +} + func runInit(cmd *cobra.Command, _ []string) error { cfgPath := "molecule.yaml" if _, err := os.Stat(cfgPath); err == nil { + if initForce { + content := `# molecule CLI configuration — https://github.com/Molecule-AI/molecule-cli +# +# All values can be overridden by environment variables: +# MOLECULE_API_URL, MOLECULE_RUNTIME_URL, MOL_OUTPUT, MOL_VERBOSE, etc. +# +# Environment variables always take precedence over this file. + +# Platform API base URL (env: MOLECULE_API_URL) +# api_url: https://api.molecule.ai + +# Workspace runtime URL for dev/proxy mode (env: MOLECULE_RUNTIME_URL) +# runtime_url: https://runtime.molecule.ai + +# Output format: table | json | yaml (env: MOL_OUTPUT) +# output: table + +# Verbose logging: true | false (env: MOL_VERBOSE) +# verbose: false +` + if err := os.WriteFile(cfgPath, []byte(content), 0o644); err != nil { + return fmt.Errorf("init: write %s: %w", cfgPath, err) + } + absPath, _ := filepath.Abs(cfgPath) + fmt.Printf("Replaced %s\n", absPath) + return nil + } return fmt.Errorf("init: %s already exists — not overwriting (use --force to replace)", cfgPath) }