diff --git a/cmd/lagoon-linter/main.go b/cmd/lagoon-linter/main.go index bda7927..a7241ee 100644 --- a/cmd/lagoon-linter/main.go +++ b/cmd/lagoon-linter/main.go @@ -11,8 +11,9 @@ var ( // CLI represents the command-line interface. type CLI struct { - Validate ValidateCmd `kong:"cmd,default=1,help='(default) Validate the Lagoon YAML'"` - Version VersionCmd `kong:"cmd,help='Print version information'"` + Validate ValidateCmd `kong:"cmd,default=1,help='(default) Validate the Lagoon YAML'"` + Version VersionCmd `kong:"cmd,help='Print version information'"` + ValidateConfigMapJSON ValidateConfigMapJSONCmd `kong:"cmd,help='Validate the result of: kubectl get configmap -A -o json'"` } func main() { diff --git a/cmd/lagoon-linter/validate.go b/cmd/lagoon-linter/validate.go index cf48201..fe949b9 100644 --- a/cmd/lagoon-linter/validate.go +++ b/cmd/lagoon-linter/validate.go @@ -9,5 +9,5 @@ type ValidateCmd struct { // Run the validation of the Lagoon YAML. func (cmd *ValidateCmd) Run() error { - return lagoonyml.Lint(cmd.LagoonYAML, lagoonyml.RouteAnnotation()) + return lagoonyml.LintFile(cmd.LagoonYAML, lagoonyml.RouteAnnotation()) } diff --git a/cmd/lagoon-linter/validateconfigmapjson.go b/cmd/lagoon-linter/validateconfigmapjson.go new file mode 100644 index 0000000..10fc485 --- /dev/null +++ b/cmd/lagoon-linter/validateconfigmapjson.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/uselagoon/lagoon-linter/internal/lagoonyml" +) + +// ValidateConfigMapJSONCmd represents the validate command. +type ValidateConfigMapJSONCmd struct { + ConfigMapJSON string `kong:"default='configmap.json',help='Specify the configmap JSON file dump.'"` +} + +// ConfigMap represents an individual configmap. +type ConfigMap struct { + Data map[string]string `json:"data"` + Metadata map[string]interface{} `json:"metadata"` +} + +// ConfigMapList represents a list of configmaps. +type ConfigMapList struct { + ConfigMaps []ConfigMap `json:"items"` +} + +// Run the validation of the Lagoon YAML dumps. +func (cmd *ValidateConfigMapJSONCmd) Run() error { + // open the file + rawJSON, err := os.ReadFile(cmd.ConfigMapJSON) + if err != nil { + return fmt.Errorf("couldn't read file: %v", err) + } + var cml ConfigMapList + // unmarshal ConfigMapList + if err := json.Unmarshal(rawJSON, &cml); err != nil { + return fmt.Errorf("couldn't unmarshal JSON: %v", err) + } + // lint it + for _, cm := range cml.ConfigMaps { + if lagoonYAML, ok := cm.Data[".lagoon.yml"]; ok { + err := lagoonyml.LintYAML([]byte(lagoonYAML), + lagoonyml.RouteAnnotation()) + if err != nil { + fmt.Printf("bad .lagoon.yml: %s: %v\n", cm.Metadata["namespace"], err) + } + } + } + return nil +} diff --git a/internal/lagoonyml/lint.go b/internal/lagoonyml/lint.go index 4334d2d..fde2604 100644 --- a/internal/lagoonyml/lint.go +++ b/internal/lagoonyml/lint.go @@ -10,11 +10,11 @@ import ( // Linter validates the given Lagoon struct. type Linter func(*Lagoon) error -// Lint takes a file path, reads it, and applies `.lagoon.yml` lint policy to +// LintFile takes a file path, reads it, and applies `.lagoon.yml` lint policy to // it. Lint returns an error of type ErrLint if it finds problems with the // file, a regular error if something else went wrong, and nil if the // `.lagoon.yml` is valid. -func Lint(path string, linters ...Linter) error { +func LintFile(path string, linters ...Linter) error { var l Lagoon rawYAML, err := os.ReadFile(path) if err != nil { @@ -33,3 +33,22 @@ func Lint(path string, linters ...Linter) error { } return nil } + +// LintYAML takes a byte slice containing raw YAML and applies `.lagoon.yml` lint policy to +// it. Lint returns an error of type ErrLint if it finds problems with the +// file, a regular error if something else went wrong, and nil if the +// `.lagoon.yml` is valid. +func LintYAML(rawYAML []byte, linters ...Linter) error { + var l Lagoon + if err := yaml.Unmarshal(rawYAML, &l); err != nil { + return fmt.Errorf("couldn't unmarshal YAML: %v", err) + } + for _, linter := range linters { + if err := linter(&l); err != nil { + return &ErrLint{ + Detail: err.Error(), + } + } + } + return nil +} diff --git a/internal/lagoonyml/lint_test.go b/internal/lagoonyml/lint_test.go index c68bc18..be074b8 100644 --- a/internal/lagoonyml/lint_test.go +++ b/internal/lagoonyml/lint_test.go @@ -46,7 +46,7 @@ func TestLint(t *testing.T) { } for name, tc := range testCases { t.Run(name, func(tt *testing.T) { - err := lagoonyml.Lint(tc.input, lagoonyml.RouteAnnotation()) + err := lagoonyml.LintFile(tc.input, lagoonyml.RouteAnnotation()) if tc.valid { if err != nil { tt.Fatalf("unexpected error %v", err)