diff --git a/cmd/analyze/analyze.go b/cmd/analyze/analyze.go index 2a3f176c1a..0a04c40736 100644 --- a/cmd/analyze/analyze.go +++ b/cmd/analyze/analyze.go @@ -2,19 +2,14 @@ package analyze import ( "context" - "encoding/json" "fmt" - "github.com/k8sgpt-ai/k8sgpt/pkg/analysis" - "github.com/k8sgpt-ai/k8sgpt/pkg/analyzer" - "os" - "strings" - "github.com/fatih/color" "github.com/k8sgpt-ai/k8sgpt/pkg/ai" + "github.com/k8sgpt-ai/k8sgpt/pkg/analysis" "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" - "github.com/schollz/progressbar/v3" "github.com/spf13/cobra" "github.com/spf13/viper" + "os" ) var ( @@ -79,54 +74,25 @@ var AnalyzeCmd = &cobra.Command{ os.Exit(1) } - if len(config.Results) == 0 { - color.Green("{ \"status\": \"OK\" }") - os.Exit(0) - } - var bar = progressbar.Default(int64(len(config.Results))) - if !explain { - bar.Clear() - } - var printOutput []analyzer.Result - - for _, analysis := range config.Results { - if explain { - parsedText, err := aiClient.Parse(ctx, analysis.Error, nocache) - if err != nil { - // Check for exhaustion - if strings.Contains(err.Error(), "status code: 429") { - color.Red("Exhausted API quota. Please try again later") - os.Exit(1) - } - color.Red("Error: %v", err) - continue - } - analysis.Details = parsedText - bar.Add(1) + if explain && output != "json" { + err := config.GetAIResults(true) + if err != nil { + color.Red("Error: %v", err) + os.Exit(1) } - printOutput = append(printOutput, analysis) } // print results - for n, analysis := range printOutput { - - switch output { - case "json": - analysis.Error = analysis.Error[0:] - j, err := json.Marshal(analysis) - if err != nil { - color.Red("Error: %v", err) - os.Exit(1) - } - fmt.Println(string(j)) - default: - fmt.Printf("%s %s(%s)\n", color.CyanString("%d", n), - color.YellowString(analysis.Name), color.CyanString(analysis.ParentObject)) - for _, err := range analysis.Error { - fmt.Printf("- %s %s\n", color.RedString("Error:"), color.RedString(err)) - } - fmt.Println(color.GreenString(analysis.Details + "\n")) + switch output { + case "json": + output, err := config.JsonOutput() + if err != nil { + color.Red("Error: %v", err) + os.Exit(1) } + fmt.Println(string(output)) + default: + config.PrintOutput() } }, } diff --git a/pkg/analysis/analysis.go b/pkg/analysis/analysis.go index f2dd345132..611edb3407 100644 --- a/pkg/analysis/analysis.go +++ b/pkg/analysis/analysis.go @@ -2,10 +2,16 @@ package analysis import ( "context" + "encoding/json" + "fmt" + "github.com/fatih/color" "github.com/k8sgpt-ai/k8sgpt/pkg/ai" "github.com/k8sgpt-ai/k8sgpt/pkg/analyzer" "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" + "github.com/schollz/progressbar/v3" "github.com/spf13/viper" + "os" + "strings" ) type Analysis struct { @@ -19,6 +25,19 @@ type Analysis struct { Explain bool } +type AnalysisStatus string + +const ( + StateOK AnalysisStatus = "OK" + StateProblemDetected AnalysisStatus = "ProblemDetected" +) + +type JsonOutput struct { + Status AnalysisStatus `json:"status"` + Problems int `json:"problems"` + Results []analyzer.Result `json:"results"` +} + func (a *Analysis) RunAnalysis() error { activeFilters := viper.GetStringSlice("active_filters") @@ -70,3 +89,70 @@ func (a *Analysis) RunAnalysis() error { } return nil } + +func (a *Analysis) JsonOutput() ([]byte, error) { + var problems int + var status AnalysisStatus + for _, result := range a.Results { + problems += len(result.Error) + } + if problems > 0 { + status = StateProblemDetected + } else { + status = StateOK + } + + result := JsonOutput{ + Problems: len(a.Results), + Results: a.Results, + Status: status, + } + output, err := json.MarshalIndent(result, "", " ") + if err != nil { + return nil, fmt.Errorf("error marshalling json: %v", err) + } + return output, nil +} + +func (a *Analysis) PrintOutput() { + fmt.Println("") + if len(a.Results) == 0 { + fmt.Println(color.GreenString("No problems detected")) + } + for n, result := range a.Results { + fmt.Printf("%s %s(%s)\n", color.CyanString("%d", n), + color.YellowString(result.Name), color.CyanString(result.ParentObject)) + for _, err := range result.Error { + fmt.Printf("- %s %s\n", color.RedString("Error:"), color.RedString(err)) + } + fmt.Println(color.GreenString(result.Details + "\n")) + } +} + +func (a *Analysis) GetAIResults(progressBar bool) error { + if len(a.Results) == 0 { + return nil + } + + var bar *progressbar.ProgressBar + if progressBar { + bar = progressbar.Default(int64(len(a.Results))) + } + + for index, analysis := range a.Results { + parsedText, err := a.AIClient.Parse(a.Context, analysis.Error, a.NoCache) + if err != nil { + // Check for exhaustion + if strings.Contains(err.Error(), "status code: 429") { + color.Red("Exhausted API quota. Please try again later") + os.Exit(1) + } + color.Red("Error: %v", err) + continue + } + analysis.Details = parsedText + bar.Add(1) + a.Results[index] = analysis + } + return nil +}