Skip to content

Commit

Permalink
Adds support for new user message format for runs and linting (#106)
Browse files Browse the repository at this point in the history
Co-authored-by: Doug Mayer <[email protected]>
  • Loading branch information
TAGraves and doxavore authored Sep 10, 2024
1 parent b503846 commit 49c82b7
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 61 deletions.
30 changes: 28 additions & 2 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"io"
"net/http"
"net/url"
"strings"

"github.com/rwx-research/mint-cli/cmd/mint/config"
"github.com/rwx-research/mint-cli/internal/accesstoken"
"github.com/rwx-research/mint-cli/internal/errors"
"github.com/rwx-research/mint-cli/internal/messages"
)

// Client is an API Client for Mint
Expand Down Expand Up @@ -367,15 +369,39 @@ func (c Client) GetLeafVersions() (*LeafVersionsResult, error) {
return &respBody, nil
}

type ErrorMessage struct {
Message string `json:"message"`
StackTrace []messages.StackEntry `json:"stack_trace,omitempty"`
Frame string `json:"frame"`
Advice string `json:"advice"`
}

// extractErrorMessage is a small helper function for parsing an API error message
func extractErrorMessage(reader io.Reader) string {
errorStruct := struct {
Error string
Error string `json:"error,omitempty"`
ErrorMessages []ErrorMessage `json:"error_messages,omitempty"`
}{}

if err := json.NewDecoder(reader).Decode(&errorStruct); err != nil {
return ""
}

return errorStruct.Error
if len(errorStruct.ErrorMessages) > 0 {
var message strings.Builder
for _, errorMessage := range errorStruct.ErrorMessages {
message.WriteString("\n\n")
message.WriteString(messages.FormatUserMessage(errorMessage.Message, errorMessage.Frame, errorMessage.StackTrace, errorMessage.Advice))
}

return message.String()
}

// Fallback to Error field
if errorStruct.Error != "" {
return errorStruct.Error
}

// Fallback to an empty string
return ""
}
44 changes: 32 additions & 12 deletions internal/api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/rwx-research/mint-cli/internal/accesstoken"
"github.com/rwx-research/mint-cli/internal/errors"
"github.com/rwx-research/mint-cli/internal/messages"
)

type Config struct {
Expand Down Expand Up @@ -70,26 +71,45 @@ func (c LintConfig) Validate() error {
}

type LintProblem struct {
Severity string `json:"severity"`
Message string `json:"message"`
FileName string `json:"file_name"`
Line NullInt `json:"line"`
Column NullInt `json:"column"`
Advice string `json:"advice"`
Severity string `json:"severity"`
Message string `json:"message"`
FileName string `json:"file_name"`
Line NullInt `json:"line"`
Column NullInt `json:"column"`
Advice string `json:"advice"`
StackTrace []messages.StackEntry `json:"stack_trace,omitempty"`
Frame string `json:"frame"`
}

func (lf LintProblem) FileLocation() string {
if len(lf.FileName) > 0 {
fileName := lf.FileName
line := lf.Line
column := lf.Column

if (len(lf.StackTrace) > 0) {
lastStackEntry := lf.StackTrace[len(lf.StackTrace) - 1]
fileName = lastStackEntry.FileName
line = NullInt{
Value: lastStackEntry.Line,
IsNull: false,
}
column = NullInt{
Value: lastStackEntry.Column,
IsNull: false,
}
}

if len(fileName) > 0 {
var buf bytes.Buffer
w := io.Writer(&buf)

fmt.Fprint(w, lf.FileName)
fmt.Fprint(w, fileName)

if !lf.Line.IsNull {
fmt.Fprintf(w, ":%d", lf.Line.Value)
if !line.IsNull {
fmt.Fprintf(w, ":%d", line.Value)
}
if !lf.Column.IsNull {
fmt.Fprintf(w, ":%d", lf.Column.Value)
if !column.IsNull {
fmt.Fprintf(w, ":%d", column.Value)
}

return buf.String()
Expand Down
64 changes: 28 additions & 36 deletions internal/cli/service.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cli

import (
"cmp"
"encoding/json"
"fmt"
"io"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/rwx-research/mint-cli/internal/api"
"github.com/rwx-research/mint-cli/internal/dotenv"
"github.com/rwx-research/mint-cli/internal/errors"
"github.com/rwx-research/mint-cli/internal/messages"

"github.com/briandowns/spinner"
"golang.org/x/crypto/ssh"
Expand Down Expand Up @@ -158,7 +158,7 @@ func (s Service) InitiateRun(cfg InitiateRunConfig) (*api.InitiateRunResult, err
UseCache: !cfg.NoCache,
})
if err != nil {
return nil, errors.Wrap(err, "unable to initiate run")
return nil, errors.Wrap(err, "Failed to initiate run")
}

return runResult, nil
Expand Down Expand Up @@ -258,9 +258,9 @@ func (s Service) Lint(cfg LintConfig) (*api.LintResult, error) {

switch cfg.OutputFormat {
case LintOutputOneLine:
err = outputLintOneLine(cfg.Output, sortLintProblems(lintResult.Problems))
err = outputLintOneLine(cfg.Output, lintResult.Problems)
case LintOutputMultiLine:
err = outputLintMultiLine(cfg.Output, sortLintProblems(lintResult.Problems), len(targetPaths))
err = outputLintMultiLine(cfg.Output, lintResult.Problems, len(targetPaths))
}
if err != nil {
return nil, errors.Wrap(err, "unable to output lint results")
Expand All @@ -270,32 +270,40 @@ func (s Service) Lint(cfg LintConfig) (*api.LintResult, error) {
}

func outputLintMultiLine(w io.Writer, problems []api.LintProblem, fileCount int) error {
for i, lf := range problems {
if i > 0 {
for _, lf := range problems {
fmt.Fprintln(w)

if len(lf.StackTrace) > 0 {
fmt.Fprint(w, "[", lf.Severity, "] ")
fmt.Fprintln(w, messages.FormatUserMessage(lf.Message, lf.Frame, lf.StackTrace, lf.Advice))
} else {
if fileLoc := lf.FileLocation(); len(fileLoc) > 0 {
fmt.Fprint(w, fileLoc, " ")
}
fmt.Fprint(w, "[", lf.Severity, "]")
fmt.Fprintln(w)
}

if fileLoc := lf.FileLocation(); len(fileLoc) > 0 {
fmt.Fprint(w, fileLoc, " ")
}
fmt.Fprint(w, "[", lf.Severity, "]")
fmt.Fprintln(w)
fmt.Fprint(w, lf.Message)

fmt.Fprint(w, lf.Message)
if len(lf.Advice) > 0 {
fmt.Fprint(w, "\n", lf.Advice)
}

if len(lf.Advice) > 0 {
fmt.Fprint(w, "\n", lf.Advice)
fmt.Fprintln(w)
}

fmt.Fprintln(w)
}

pluralized := "problems"
pluralizedProblems := "problems"
if len(problems) == 1 {
pluralized = "problem"
pluralizedProblems = "problem"
}

pluralizedFiles := "files"
if fileCount == 1 {
pluralizedFiles = "file"
}

fmt.Fprintf(w, "\nChecked %d files and found %d %s.\n", fileCount, len(problems), pluralized)
fmt.Fprintf(w, "\nChecked %d %s and found %d %s.\n", fileCount, pluralizedFiles, len(problems), pluralizedProblems)

return nil
}
Expand All @@ -319,22 +327,6 @@ func outputLintOneLine(w io.Writer, lintedFiles []api.LintProblem) error {
return nil
}

func sortLintProblems(problems []api.LintProblem) []api.LintProblem {
sortedProblems := append([]api.LintProblem(nil), problems...)
slices.SortFunc(sortedProblems, func(a, b api.LintProblem) int {
if n := cmp.Compare(a.FileName, b.FileName); n != 0 {
return n
}

if n := cmp.Compare(a.Line.Value, b.Line.Value); n != 0 {
return n
}

return cmp.Compare(a.Column.Value, b.Column.Value)
})
return sortedProblems
}

// InitiateRun will connect to the Cloud API and start a new run in Mint.
func (s Service) Login(cfg LoginConfig) error {
err := cfg.Validate()
Expand Down
Loading

0 comments on commit 49c82b7

Please sign in to comment.