Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ kploy auth whoami # show the orgs your token can see
kploy auth logout # forget the saved token
```

## Validating `kploy.yaml`

If your project has a `kploy.yaml` at its repo root, you can sanity-check it locally before pushing:

```sh
kploy validate-config # defaults to ./kploy.yaml
kploy validate-config -f my.yaml # different path
```

Prints rendered hostnames for production and development on success — plus an example preview env if preview environments are enabled. Validation errors include the field path. Does not require authentication.

## Common workflows

```sh
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func Root() *cobra.Command {
root.AddCommand(imageCommand())
root.AddCommand(orgCommand())
root.AddCommand(repoCommand())
root.AddCommand(validateConfigCommand())
root.AddCommand(versionCommand())

return root
Expand Down
102 changes: 102 additions & 0 deletions cmd/validate_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package cmd

import (
"errors"
"fmt"
"os"
"text/tabwriter"

"github.com/bitcomplete/kployconfig"
"github.com/spf13/cobra"
)

func validateConfigCommand() *cobra.Command {
var file string
c := &cobra.Command{
Use: "validate-config",
Short: "Validate a local kploy.yaml file",
Long: `Parse and validate a kploy.yaml file, then print the hostnames
it would render for production and development — plus, if preview
environments are enabled, an example PR preview env.`,
RunE: func(c *cobra.Command, args []string) error {
data, err := os.ReadFile(file)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("no %s in current directory; use --file to point elsewhere", file)
}
return fmt.Errorf("reading %s: %w", file, err)
}
cfg, err := kployconfig.Load(data)
if err != nil {
return err
}

envs := []struct {
name string
pr int
}{
{"prod", 0},
{"development", 0},
}
hostnames := make(map[string]string, len(envs))
for _, env := range envs {
h, err := kployconfig.RenderHostname(cfg, env.name, env.pr)
if err != nil {
return fmt.Errorf("render %s: %w", env.name, err)
}
hostnames[env.name] = h
}

var ingress []kployconfig.IngressHostname
if cfg.Preview != nil && cfg.Preview.Enabled {
ingress, err = kployconfig.RenderPreviewIngress(cfg, 1)
if err != nil {
return err
}
}

out := c.OutOrStdout()
if outputFormat == "json" {
return renderJSON(out, struct {
Valid bool `json:"valid"`
Project string `json:"project"`
Hostnames map[string]string `json:"hostnames"`
PreviewIngress []kployconfig.IngressHostname `json:"previewIngress,omitempty"`
}{
Valid: true,
Project: cfg.Project,
Hostnames: hostnames,
PreviewIngress: ingress,
})
}

_, _ = fmt.Fprintln(out, "OK")
_, _ = fmt.Fprintln(out)
_, _ = fmt.Fprintln(out, "Sample hostnames:")
tw := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
_, _ = fmt.Fprintln(tw, "ENV\tHOSTNAME")
for _, env := range envs {
_, _ = fmt.Fprintf(tw, "%s\t%s\n", env.name, hostnames[env.name])
}
if err := tw.Flush(); err != nil {
return err
}

if len(ingress) > 0 {
_, _ = fmt.Fprintln(out)
_, _ = fmt.Fprintln(out, "Example preview env (PR #1):")
tw2 := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
_, _ = fmt.Fprintln(tw2, "HOSTNAME\tSERVICE\tPORT")
for _, ing := range ingress {
_, _ = fmt.Fprintf(tw2, "%s\t%s\t%d\n", ing.Hostname, ing.ServiceName, ing.ServicePort)
}
if err := tw2.Flush(); err != nil {
return err
}
}
return nil
},
}
c.Flags().StringVarP(&file, "file", "f", "kploy.yaml", "Path to kploy.yaml")
return c
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.24.3
tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen

require (
github.com/bitcomplete/kployconfig v0.1.1
github.com/oapi-codegen/runtime v1.4.0
github.com/spf13/cobra v1.10.1
go.yaml.in/yaml/v3 v3.0.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bitcomplete/kployconfig v0.1.1 h1:3eMolFvB7Jn8/NFdfIatxVwEflvLjJbKxDe+BPCnvfY=
github.com/bitcomplete/kployconfig v0.1.1/go.mod h1:qyAG3qodAW45q7CXYtLe3oBcB5DVL1Q2YtdvJw01QUs=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand Down
Loading