package recipe import ( "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/i18n" "coopcloud.tech/abra/pkg/lint" "coopcloud.tech/abra/pkg/log" "github.com/spf13/cobra" ) var RecipeLintCommand = &cobra.Command{ Use: i18n.G("lint [flags]"), Short: i18n.G("Lint a recipe"), Aliases: []string{i18n.G("l")}, Args: cobra.MinimumNArgs(1), ValidArgsFunction: func( cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return autocomplete.RecipeNameComplete() }, Run: func(cmd *cobra.Command, args []string) { recipe := internal.ValidateRecipe(args, cmd.Name()) if err := recipe.Ensure(internal.GetEnsureContext()); err != nil { log.Fatal(err) } headers := []string{ i18n.G("ref"), i18n.G("rule"), i18n.G("severity"), i18n.G("satisfied"), i18n.G("skipped"), i18n.G("resolve"), } table, err := formatter.CreateTable() 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 onlyError && rule.Level != "error" { log.Debug(i18n.G("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 == i18n.G("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 { if err := formatter.PrintTable(table); err != nil { log.Fatal(err) } for _, warnMsg := range warnMessages { log.Warn(warnMsg) } if hasError { log.Warn(i18n.G("critical errors present in %s config", recipe.Name)) } } }, } var ( onlyError bool ) func init() { RecipeLintCommand.Flags().BoolVarP( &internal.Chaos, i18n.G("chaos"), i18n.G("C"), false, i18n.G("ignore uncommitted recipes changes"), ) RecipeLintCommand.Flags().BoolVarP( &onlyError, i18n.G("error"), i18n.G("e"), false, i18n.G("only show errors"), ) }