Skip to content

Commit

Permalink
Added extended parameter checks (#1715)
Browse files Browse the repository at this point in the history
* Added extended parameter checks

Signed-off-by: Andreas Neumann <aneumann@mesosphere.com>
  • Loading branch information
ANeumann82 committed Oct 21, 2020
1 parent 027e1d2 commit 21f49a3
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 9 deletions.
3 changes: 2 additions & 1 deletion pkg/kudoctl/cmd/package_create.go
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/spf13/cobra"

"github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/writer"
)

Expand Down Expand Up @@ -73,7 +74,7 @@ func validateOperatorArg(args []string) error {

// run returns the errors associated with cmd env
func (pkg *packageCreateCmd) run() error {
err := verifyPackage(pkg.fs, pkg.path, pkg.out, pkg.output)
err := verifyPackage(pkg.fs, pkg.path, pkg.out, pkg.output, []packages.Verifier{})
if err != nil {
return err
}
Expand Down
22 changes: 16 additions & 6 deletions pkg/kudoctl/cmd/package_verify.go
Expand Up @@ -9,15 +9,18 @@ import (

"github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output"
"github.com/kudobuilder/kudo/pkg/kudoctl/cmd/verify"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/reader"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier/template"
)

// package verify provides verification or linting checks against the package passed to the command.

type packageVerifyCmd struct {
fs afero.Fs
out io.Writer
output output.Type
fs afero.Fs
out io.Writer
output output.Type
paramChecks []string
}

func newPackageVerifyCmd(fs afero.Fs, out io.Writer) *cobra.Command {
Expand All @@ -37,23 +40,30 @@ func newPackageVerifyCmd(fs afero.Fs, out io.Writer) *cobra.Command {
}

cmd.Flags().StringVarP((*string)(&verifyCmd.output), "output", "o", "", "Output format for command results.")

cmd.Flags().StringSliceVar(&verifyCmd.paramChecks, "param-checks", []string{}, fmt.Sprintf("Additional parameter checks: %v", template.ParamVerifyArguments))
return cmd
}

func (c *packageVerifyCmd) run(path string) error {
if err := c.output.Validate(); err != nil {
return err
}
return verifyPackage(c.fs, path, c.out, c.output)
opts := template.ExtendedParametersVerifier{}
if err := opts.SetFromArguments(c.paramChecks); err != nil {
return err
}
return verifyPackage(c.fs, path, c.out, c.output, []packages.Verifier{&opts})
}

func verifyPackage(fs afero.Fs, path string, out io.Writer, outType output.Type) error {
func verifyPackage(fs afero.Fs, path string, out io.Writer, outType output.Type, additionalVerifiers []packages.Verifier) error {
pf, err := reader.PackageFilesFromDir(fs, path)
if err != nil {
return err
}
res := verify.PackageFiles(pf)
for _, v := range additionalVerifiers {
res.Merge(v.Verify(pf))
}

if outType != "" {
if err = output.WriteObject(res.ForOutput(), outType, out); err != nil {
Expand Down
211 changes: 211 additions & 0 deletions pkg/kudoctl/packages/verifier/template/verify_extended_parameters.go
@@ -0,0 +1,211 @@
package template

import (
"fmt"
"strings"
"unicode"

"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

var _ packages.Verifier = &ExtendedParametersVerifier{}

type ParamVerifyArgumentType string

const (
ParamVerifyDisplayName ParamVerifyArgumentType = "display"
ParamVerifyHint ParamVerifyArgumentType = "hint"
ParamVerifyDescription ParamVerifyArgumentType = "desc"
ParamVerifyType ParamVerifyArgumentType = "type"
ParamVerifyHasGroup ParamVerifyArgumentType = "hasgroup"
ParamVerifyGroups ParamVerifyArgumentType = "groups"
ParamVerifyAll ParamVerifyArgumentType = "all"
)

var (
ParamVerifyArguments = []ParamVerifyArgumentType{
ParamVerifyDisplayName,
ParamVerifyHint,
ParamVerifyDescription,
ParamVerifyType,
ParamVerifyHasGroup,
ParamVerifyGroups,
ParamVerifyAll,
}
)

type ExtendedParametersVerifier struct {
VerifyParamDescription bool
VerifyParamHint bool
VerifyParamDisplayName bool
VerifyParamType bool
VerifyParamGroup bool
VerifyGroups bool
}

func (v *ExtendedParametersVerifier) SetFromArguments(args []string) error {
for _, c := range args {

switch ParamVerifyArgumentType(c) {
case ParamVerifyDisplayName:
v.VerifyParamDisplayName = true
case ParamVerifyHint:
v.VerifyParamHint = true
case ParamVerifyDescription:
v.VerifyParamDescription = true
case ParamVerifyType:
v.VerifyParamType = true
case ParamVerifyHasGroup:
v.VerifyParamGroup = true
case ParamVerifyGroups:
v.VerifyGroups = true
case ParamVerifyAll:
v.VerifyParamDisplayName = true
v.VerifyParamHint = true
v.VerifyParamDescription = true
v.VerifyParamType = true
v.VerifyParamGroup = true
v.VerifyGroups = true
default:
return fmt.Errorf("unknown parameter check: %s, must be one of %v", c, ParamVerifyArguments)
}
}
return nil
}

// Verify implements packages.Verifier for parameter verification
func (v *ExtendedParametersVerifier) Verify(pf *packages.Files) verifier.Result {

res := verifier.NewResult()
if v.VerifyParamDescription {
res.Merge(v.verifyDescription(pf))
}
if v.VerifyParamHint {
res.Merge(v.verifyHint(pf))
}
if v.VerifyParamDisplayName {
res.Merge(v.verifyDisplayName(pf))
}
if v.VerifyParamGroup {
res.Merge(v.verifyParamGroup(pf))
}
if v.VerifyParamType {
res.Merge(v.verifyType(pf))
}
if v.VerifyGroups {
res.Merge(v.verifyGroups(pf))
}
return res
}

func (ExtendedParametersVerifier) verifyDescription(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, p := range pf.Params.Parameters {
if ok, msg := validDescription(p.Description); !ok {
res.AddParamWarning(p.Name, msg)
}
}
return res
}

func (ExtendedParametersVerifier) verifyDisplayName(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, p := range pf.Params.Parameters {
if ok, msg := validDisplayName(p.DisplayName); !ok {
res.AddParamWarning(p.Name, msg)
}
}
return res
}

func (ExtendedParametersVerifier) verifyHint(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, p := range pf.Params.Parameters {
if ok, msg := validHint(p.Hint); !ok {
res.AddParamWarning(p.Name, msg)
}
}
return res
}

func (v ExtendedParametersVerifier) verifyParamGroup(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, p := range pf.Params.Parameters {
if p.Group == "" {
res.AddParamWarning(p.Name, "has no group")
}
// The check if a specified group is defined in the groups section is in verify_parameters.go, as it
// is a required check and not an optional one.
}
return res
}

func (v ExtendedParametersVerifier) verifyGroups(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, g := range pf.Params.Groups {
if ok, msg := validDisplayName(g.DisplayName); !ok {
res.AddGroupWarning(g.Name, msg)
}
if ok, msg := validDescription(g.Description); !ok {
res.AddGroupWarning(g.Name, msg)
}
}
return res
}

func (ExtendedParametersVerifier) verifyType(pf *packages.Files) verifier.Result {
res := verifier.NewResult()
for _, p := range pf.Params.Parameters {
if p.Type == "" {
res.AddParamWarning(p.Name, "has no explicit type assigned")
}
}
return res
}

func validDisplayName(displayName string) (bool, string) {
if displayName == "" {
return false, "has no displayName"
}
if strings.HasSuffix(displayName, ":") {
return false, "has a displayName ending with ':'"
}
if !IsUpper(displayName[0:1]) {
return false, "has a displayName that does not start with a capital letter"
}
return true, ""
}

func validDescription(description string) (bool, string) {
if description == "" {
return false, "has no description"
}
lastChar := description[len(description)-1:]
if !strings.Contains(".!?)", lastChar) {
return false, "has a description not ending with one of '.!?)'"
}
if !IsUpper(description[0:1]) {
return false, "has a description that does not start with a capital letter"
}
return true, ""
}

func validHint(hint string) (bool, string) {
if hint == "" {
return false, "has no hint"
}
if !strings.HasSuffix(hint, ".") {
return false, "has a hint not ending with a '.'"
}
return true, ""
}

func IsUpper(s string) bool {
for _, r := range s {
if !unicode.IsUpper(r) && unicode.IsLetter(r) {
return false
}
}
return true
}

0 comments on commit 21f49a3

Please sign in to comment.