package recipe import ( "fmt" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/lint" "coopcloud.tech/abra/pkg/log" "github.com/urfave/cli" ) var recipeLintCommand = cli.Command{ Name: "lint", Usage: "Lint a recipe", Aliases: []string{"l"}, ArgsUsage: "", Flags: []cli.Flag{ internal.DebugFlag, internal.OnlyErrorFlag, internal.OfflineFlag, internal.NoInputFlag, internal.ChaosFlag, }, Before: internal.SubCommandBefore, BashComplete: autocomplete.RecipeNameComplete, Action: func(c *cli.Context) error { recipe := internal.ValidateRecipe(c) if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil { log.Fatal(err) } headers := []string{ "ref", "rule", "severity", "satisfied", "skipped", "resolve", } table, err := formatter.CreateTable2() if err != nil { log.Fatal(err) } table.Headers(headers...) hasError := false var rows [][]string var warnMessages []string for level := range lint.LintRules { for _, rule := range lint.LintRules[level] { if internal.OnlyErrors && rule.Level != "error" { log.Debugf("skipping %s, does not have level \"error\"", rule.Ref) continue } skipped := false if rule.Skip(recipe) { skipped = true } skippedOutput := "-" if skipped { skippedOutput = "✅" } satisfied := false if !skipped { ok, err := rule.Function(recipe) if err != nil { warnMessages = append(warnMessages, err.Error()) } if !ok && rule.Level == "error" { hasError = true } if ok { satisfied = true } } satisfiedOutput := "✅" if !satisfied { satisfiedOutput = "❌" if skipped { satisfiedOutput = "-" } } row := []string{ rule.Ref, rule.Description, rule.Level, satisfiedOutput, skippedOutput, rule.HowToResolve, } rows = append(rows, row) table.Row(row...) } } if len(rows) > 0 { fmt.Println(table) for _, warnMsg := range warnMessages { log.Warn(warnMsg) } if hasError { log.Warnf("critical errors present in %s config", recipe.Name) } } return nil }, }