diff --git a/.gitignore b/.gitignore index 832dca7..61a48bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -# ----------------------------- # Go / Build / Binary files -# ----------------------------- *.o *.a *.so @@ -15,9 +13,7 @@ cobra.test bin/ dist/ -# ----------------------------- # Project specific / temporary -# ----------------------------- output.json output.yaml output.xml @@ -31,9 +27,7 @@ config.yaml # pkg/prompt folder (included for interactive prompts) # pkg/prompt/ <- commented out so files are tracked -# ----------------------------- # IDE / Editor -# ----------------------------- .idea/ .vscode/ *.iml @@ -42,20 +36,12 @@ Session.vim .netrwhist *~ -# ----------------------------- -# Other generated files / folders -# ----------------------------- +# Generated binaries and build outputs codewise-cli myapp/ myapp/codewise codewise myappcodewise-cli -codewise-cli -JTY_output.yaml -KVTJ_output.json -YTJ_output.json -# ----------------------------- # Environment files -# ----------------------------- .env diff --git a/README.md b/README.md index f3de82e..4ad8107 100644 --- a/README.md +++ b/README.md @@ -162,18 +162,23 @@ helm/chart/ Usage: ```bash -codewise encode --input file --output out --type +codewise encode --input file --output out [flags] ``` -Supported modes: +Common conversions: -| mode | description | -| ------ | ------------- | -| `JTY` | JSON → YAML | -| `YTJ` | YAML → JSON | -| `KVTJ` | .env → JSON | -| `B64E` | Base64 encode | -| `B64D` | Base64 decode | +| command example | description | +| --------------- | ----------- | +| `codewise encode -i app.json -o app.yaml --json-to-yaml` | JSON → YAML | +| `codewise encode -i app.yaml -o app.json` | YAML → JSON (default path) | +| `codewise encode -i .env -o env.json --env-to-json` | .env → JSON | +| `codewise encode -i input.txt -o encoded.txt --base64` | Base64 encode | +| `codewise encode -i encoded.txt -o output.txt --base64 --decode` | Base64 decode | + +Additional auto-detected conversions are supported from file extensions: + +- TOML ⇄ JSON +- XML ⇄ JSON --- diff --git a/cmd/deploy.go b/cmd/deploy.go index 2cfe22c..6a9e541 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "github.com/aryansharma9917/codewise-cli/pkg/deploy" "github.com/spf13/cobra" @@ -20,32 +19,22 @@ var deployCmd = &cobra.Command{ var deployRunCmd = &cobra.Command{ Use: "run", Short: "Execute deployment", - Run: func(cmd *cobra.Command, args []string) { - + RunE: func(cmd *cobra.Command, args []string) error { if deployEnv == "" { - fmt.Println("please provide --env") - return - } - - if err := deploy.Run(deployEnv, dryRun); err != nil { - fmt.Println("deploy error:", err) + return ExitError("please provide --env") } + return deploy.Run(deployEnv, dryRun) }, } var deployPlanCmd = &cobra.Command{ Use: "plan", Short: "Preview deployment execution plan", - Run: func(cmd *cobra.Command, args []string) { - + RunE: func(cmd *cobra.Command, args []string) error { if deployEnv == "" { - fmt.Println("please provide --env") - return - } - - if err := deploy.Plan(deployEnv); err != nil { - fmt.Println("plan error:", err) + return ExitError("please provide --env") } + return deploy.Plan(deployEnv) }, } diff --git a/cmd/doctor.go b/cmd/docker.go similarity index 70% rename from cmd/doctor.go rename to cmd/docker.go index 096773c..e8089ee 100644 --- a/cmd/doctor.go +++ b/cmd/docker.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "github.com/aryansharma9917/codewise-cli/pkg/docker" "github.com/spf13/cobra" @@ -17,32 +16,35 @@ var dockerCmd = &cobra.Command{ var dockerInitCmd = &cobra.Command{ Use: "init", Short: "Generate a Dockerfile", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if err := docker.InitDockerfile(); err != nil { - fmt.Println("ℹ️", err.Error()) - return + return LogError(err.Error()) } - fmt.Println("✅ Dockerfile created") + LogSuccess("Dockerfile created") + return nil }, } var dockerValidateCmd = &cobra.Command{ Use: "validate", Short: "Validate Dockerfile best practices", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if err := docker.ValidateDockerfile(); err != nil { - fmt.Println("❌", err.Error()) + return LogError(err.Error()) } + return nil }, } var dockerBuildCmd = &cobra.Command{ Use: "build", Short: "Build Docker image", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if err := docker.BuildDockerImage(imageTag); err != nil { - fmt.Println("❌ Docker build failed") + return LogError("Docker build failed: %v", err) } + LogSuccess("Docker image built successfully") + return nil }, } diff --git a/cmd/env_create.go b/cmd/env_create.go index a5bd479..e267612 100644 --- a/cmd/env_create.go +++ b/cmd/env_create.go @@ -15,23 +15,22 @@ var envCreateCmd = &cobra.Command{ Use: "create ", Short: "Create a new environment", Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { name := args[0] if interactive { if err := createEnvInteractive(name); err != nil { - fmt.Println("error:", err) - return + return LogError("error: %v", err) } - fmt.Println("environment", name, "created") - return + LogSuccess("environment %s created", name) + return nil } if err := env.CreateEnv(name, env.CreateOptions{}); err != nil { - fmt.Println("error:", err) - return + return LogError("error: %v", err) } - fmt.Println("environment", name, "created") + LogSuccess("environment %s created", name) + return nil }, } diff --git a/cmd/env_delete.go b/cmd/env_delete.go index 1d9202a..1679386 100644 --- a/cmd/env_delete.go +++ b/cmd/env_delete.go @@ -14,7 +14,7 @@ var envDeleteCmd = &cobra.Command{ Use: "delete ", Short: "Delete an environment", Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { name := args[0] if !yes { @@ -23,21 +23,19 @@ var envDeleteCmd = &cobra.Command{ Message: fmt.Sprintf("Delete environment %q?", name), } if err := survey.AskOne(prompt, &confirm); err != nil { - fmt.Println("error:", err) - return + return LogError("error: %v", err) } if !confirm { - fmt.Println("aborted") - return + return LogError("aborted") } } if err := env.DeleteEnv(name, env.DeleteOptions{Force: yes}); err != nil { - fmt.Println("error:", err) - return + return LogError("error: %v", err) } - fmt.Println("environment", name, "deleted") + LogSuccess("environment %s deleted", name) + return nil }, } diff --git a/cmd/env_list.go b/cmd/env_list.go index eb4d9ea..49b38d3 100644 --- a/cmd/env_list.go +++ b/cmd/env_list.go @@ -1,34 +1,34 @@ package cmd import ( - "fmt" +"fmt" - "github.com/aryansharma9917/codewise-cli/pkg/env" - "github.com/spf13/cobra" +"github.com/aryansharma9917/codewise-cli/pkg/env" +"github.com/spf13/cobra" ) var envListCmd = &cobra.Command{ - Use: "list", - Short: "List environments", - Run: func(cmd *cobra.Command, args []string) { - envs, err := env.ListEnvs() - if err != nil { - fmt.Println("error:", err) - return - } +Use: "list", +Short: "List environments", +RunE: func(cmd *cobra.Command, args []string) error { +envs, err := env.ListEnvs() +if err != nil { +return LogError(err.Error()) +} - if len(envs) == 0 { - fmt.Println("no environments found") - return - } +if len(envs) == 0 { +fmt.Println("no environments found") +return nil +} - for _, e := range envs { - fmt.Printf("%-10s namespace=%s context=%s\n", - e.Name, e.K8s.Namespace, e.K8s.Context) - } - }, +for _, e := range envs { +fmt.Printf("%-10s namespace=%s context=%s\n", +e.Name, e.K8s.Namespace, e.K8s.Context) +} +return nil +}, } func init() { - envCmd.AddCommand(envListCmd) +envCmd.AddCommand(envListCmd) } diff --git a/cmd/errors.go b/cmd/errors.go new file mode 100644 index 0000000..0dfd947 --- /dev/null +++ b/cmd/errors.go @@ -0,0 +1,29 @@ +package cmd + +import ( + "fmt" + "os" +) + +// ExitError prints an error message and exits with status code 1. +func ExitError(format string, args ...interface{}) error { + fmt.Fprintf(os.Stderr, "error: %s\n", fmt.Sprintf(format, args...)) + return fmt.Errorf(format, args...) +} + +// LogError prints an info/warning message but does not exit. +func LogError(format string, args ...interface{}) error { + msg := fmt.Sprintf(format, args...) + fmt.Fprintf(os.Stderr, "info: %s\n", msg) + return fmt.Errorf(msg) +} + +// LogInfo prints an info message to stderr. +func LogInfo(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "info: %s\n", fmt.Sprintf(format, args...)) +} + +// LogSuccess prints a success message to stdout. +func LogSuccess(format string, args ...interface{}) { + fmt.Printf("✅ %s\n", fmt.Sprintf(format, args...)) +} diff --git a/cmd/k8s_apply.go b/cmd/k8s_apply.go index 51c3261..5a64dcf 100644 --- a/cmd/k8s_apply.go +++ b/cmd/k8s_apply.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "github.com/aryansharma9917/codewise-cli/pkg/k8s" "github.com/spf13/cobra" @@ -16,23 +15,16 @@ var ( var k8sApplyCmd = &cobra.Command{ Use: "apply", Short: "Apply Kubernetes manifests to the current cluster", - Run: func(cmd *cobra.Command, args []string) { - // If not a dry run, check cluster connectivity + RunE: func(cmd *cobra.Command, args []string) error { if !k8sDryRun { if err := k8s.CheckKubectl(); err != nil { - fmt.Println("info:", err.Error()) - return + return LogError(err.Error()) } if err := k8s.CheckCluster(); err != nil { - fmt.Println("info:", err.Error()) - return + return LogError(err.Error()) } } - - if err := k8s.ApplyManifests(k8sNamespace, k8sContext, k8sDryRun); err != nil { - fmt.Println("info:", err.Error()) - return - } + return k8s.ApplyManifests(k8sNamespace, k8sContext, k8sDryRun) }, } diff --git a/cmd/k8s_delete.go b/cmd/k8s_delete.go index e650be5..d42545f 100644 --- a/cmd/k8s_delete.go +++ b/cmd/k8s_delete.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "github.com/aryansharma9917/codewise-cli/pkg/k8s" "github.com/spf13/cobra" @@ -16,22 +15,16 @@ var ( var k8sDeleteCmd = &cobra.Command{ Use: "delete", Short: "Delete Kubernetes resources from the current cluster", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if !k8sDeleteDryRun { if err := k8s.CheckKubectl(); err != nil { - fmt.Println("info:", err.Error()) - return + return LogError(err.Error()) } if err := k8s.CheckCluster(); err != nil { - fmt.Println("info:", err.Error()) - return + return LogError(err.Error()) } } - - if err := k8s.DeleteManifests(k8sDeleteNamespace, k8sDeleteContext, k8sDeleteDryRun); err != nil { - fmt.Println("info:", err.Error()) - return - } + return k8s.DeleteManifests(k8sDeleteNamespace, k8sDeleteContext, k8sDeleteDryRun) }, } diff --git a/cmd/k8s_init.go b/cmd/k8s_init.go new file mode 100644 index 0000000..e7c1530 --- /dev/null +++ b/cmd/k8s_init.go @@ -0,0 +1,36 @@ +package cmd + +import ( + + "github.com/aryansharma9917/codewise-cli/pkg/k8s" + "github.com/spf13/cobra" +) + +var ( + k8sInitAppName string + k8sInitImage string +) + +var k8sInitCmd = &cobra.Command{ + Use: "init", + Short: "Initialize Kubernetes deployment and service manifests", + RunE: func(cmd *cobra.Command, args []string) error { + opts := k8s.Options{ + AppName: k8sInitAppName, + Image: k8sInitImage, + } + + if err := k8s.InitK8sManifests(opts); err != nil { + return LogError(err.Error()) + } + + LogSuccess("k8s manifests created at k8s/app") + return nil + }, +} + +func init() { + k8sInitCmd.Flags().StringVar(&k8sInitAppName, "app", "", "Application name for manifests") + k8sInitCmd.Flags().StringVar(&k8sInitImage, "image", "", "Container image for manifests") + k8sCmd.AddCommand(k8sInitCmd) +} diff --git a/cmd/root.go b/cmd/root.go index 7221093..5cd9d35 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -28,7 +28,7 @@ A powerful platform-style CLI for DevOps workflows including: _ = cmd.Help() }, - Version: "v1.1.0", + Version: CLI_VERSION, } // Execute runs the root command. diff --git a/cmd/version.go b/cmd/version.go index 4400c16..64e9271 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -13,8 +13,8 @@ var ( const ( CLI_VERSION = "1.7.0" - OWNER = "AryanSharma" - REPO = "codewise-cli" + OWNER = "AryanSharma9917" + REPO = "Codewise-CLI" ) // versionCmd represents the version command @@ -57,6 +57,8 @@ func checkForNewVersion() { } func init() { + rootCmd.AddCommand(versionCmd) + // Flags for the version command versionCmd.Flags().BoolVarP(&checkLatest, "latest", "l", false, "Check if the latest version is installed") } diff --git a/cmd/wiring_test.go b/cmd/wiring_test.go new file mode 100644 index 0000000..317a8cc --- /dev/null +++ b/cmd/wiring_test.go @@ -0,0 +1,39 @@ +package cmd + +import ( + "testing" + + "github.com/spf13/cobra" +) + +func findCommandByName(parent *cobra.Command, use string) *cobra.Command { + for _, c := range parent.Commands() { + if c.Name() == use { + return c + } + } + return nil +} + +func TestVersionCommandIsRegistered(t *testing.T) { + if got := findCommandByName(rootCmd, "version"); got == nil { + t.Fatalf("expected version command to be registered on root") + } +} + +func TestRootVersionMatchesConstant(t *testing.T) { + if rootCmd.Version != CLI_VERSION { + t.Fatalf("expected root version %q to match CLI version %q", rootCmd.Version, CLI_VERSION) + } +} + +func TestK8sInitCommandIsRegistered(t *testing.T) { + k8s := findCommandByName(rootCmd, "k8s") + if k8s == nil { + t.Fatalf("expected k8s command to be registered on root") + } + + if got := findCommandByName(k8s, "init"); got == nil { + t.Fatalf("expected k8s init subcommand to be registered") + } +} diff --git a/pkg/encoder/base64_encode.go b/pkg/encoder/base64_encode.go deleted file mode 100644 index f4c34ed..0000000 --- a/pkg/encoder/base64_encode.go +++ /dev/null @@ -1,3 +0,0 @@ -package encoder - -// placeholder until implemented diff --git a/pkg/validator/validate.go b/pkg/validator/validate.go index f4c34ed..2e7e343 100644 --- a/pkg/validator/validate.go +++ b/pkg/validator/validate.go @@ -1,3 +1,4 @@ -package encoder +package validator -// placeholder until implemented +// Package validator is reserved for future framework and configuration validation logic. +// Currently under planning; v2.0+ roadmap. diff --git a/testdata/JTY_output.yaml b/testdata/JTY_output.yaml new file mode 100644 index 0000000..c835a2d --- /dev/null +++ b/testdata/JTY_output.yaml @@ -0,0 +1,4 @@ +{ + "name": "Codewise", + "version": "1.0" +} \ No newline at end of file diff --git a/testdata/YTJ_output.json b/testdata/YTJ_output.json new file mode 100644 index 0000000..810d5cd --- /dev/null +++ b/testdata/YTJ_output.json @@ -0,0 +1,4 @@ +{ + "language": "Go", + "name": "Codewise" +} \ No newline at end of file diff --git a/data.json b/testdata/examples/data.json similarity index 100% rename from data.json rename to testdata/examples/data.json diff --git a/data.yaml b/testdata/examples/data.yaml similarity index 100% rename from data.yaml rename to testdata/examples/data.yaml diff --git a/encoded.txt b/testdata/examples/encoded.txt similarity index 100% rename from encoded.txt rename to testdata/examples/encoded.txt diff --git a/input.txt b/testdata/examples/input.txt similarity index 100% rename from input.txt rename to testdata/examples/input.txt diff --git a/input.yaml b/testdata/examples/input.yaml similarity index 100% rename from input.yaml rename to testdata/examples/input.yaml