Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/cli/crie_chk.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ crie chk [flags]

```
-e, --continue show all errors rather than stopping at the first
-g, --git-diff only use files from the current commit to (git-target)
-t, --git-target string the branch to compare against to find changed files (default "origin/main")
-g, --git-diff only check files changed in git
-t, --git-target string a target branch to compare against e.g 'remote/branch' or 'branch'
-h, --help help for chk
--only crie ls run with only one language (see crie ls for available options)
-p, --passes show files that passed
Expand Down
4 changes: 2 additions & 2 deletions doc/cli/crie_conf.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ crie conf [flags]

```
-e, --continue show all errors rather than stopping at the first
-g, --git-diff only use files from the current commit to (git-target)
-t, --git-target string the branch to compare against to find changed files (default "origin/main")
-g, --git-diff only check files changed in git
-t, --git-target string a target branch to compare against e.g 'remote/branch' or 'branch'
-h, --help help for conf
--only crie ls run with only one language (see crie ls for available options)
-p, --passes show files that passed
Expand Down
4 changes: 2 additions & 2 deletions doc/cli/crie_fmt.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ crie fmt [flags]

```
-e, --continue show all errors rather than stopping at the first
-g, --git-diff only use files from the current commit to (git-target)
-t, --git-target string the branch to compare against to find changed files (default "origin/main")
-g, --git-diff only check files changed in git
-t, --git-target string a target branch to compare against e.g 'remote/branch' or 'branch'
-h, --help help for fmt
--only crie ls run with only one language (see crie ls for available options)
-p, --passes show files that passed
Expand Down
4 changes: 2 additions & 2 deletions doc/cli/crie_init.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ crie init [flags]

```
-e, --continue show all errors rather than stopping at the first
-g, --git-diff only use files from the current commit to (git-target)
-t, --git-target string the branch to compare against to find changed files (default "origin/main")
-g, --git-diff only check files changed in git
-t, --git-target string a target branch to compare against e.g 'remote/branch' or 'branch'
-h, --help help for init
--only crie ls run with only one language (see crie ls for available options)
-p, --passes show files that passed
Expand Down
4 changes: 2 additions & 2 deletions doc/cli/crie_lnt.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ crie lnt [flags]

```
-e, --continue show all errors rather than stopping at the first
-g, --git-diff only use files from the current commit to (git-target)
-t, --git-target string the branch to compare against to find changed files (default "origin/main")
-g, --git-diff only check files changed in git
-t, --git-target string a target branch to compare against e.g 'remote/branch' or 'branch'
-h, --help help for lnt
--only crie ls run with only one language (see crie ls for available options)
-p, --passes show files that passed
Expand Down
39 changes: 19 additions & 20 deletions internal/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (
"strings"

"github.com/spf13/viper"
language2 "github.com/tyhal/crie/internal/config/language"
project2 "github.com/tyhal/crie/internal/config/project"
"github.com/tyhal/crie/internal/config/language"
"github.com/tyhal/crie/internal/config/project"
"github.com/tyhal/crie/internal/errchain"
"github.com/tyhal/crie/internal/runner"
"gopkg.in/yaml.v3"

Expand All @@ -20,7 +21,7 @@ import (
var crieRun runner.RunConfiguration

// SetCrie pushes the Languages to the crie.RunConfiguration
func SetCrie(proj *project2.Config, langs *language2.Languages) {
func SetCrie(proj *project.Config, langs *language.Languages) {

languages := make(map[string]*runner.Language, len(langs.Languages))
for langName, lang := range langs.Languages {
Expand All @@ -44,7 +45,7 @@ var FmtCmd = &cobra.Command{
err := crieRun.Run(runner.LintTypeFmt)

if err != nil {
log.Fatal(fmt.Errorf("crie format failed: %w", err))
log.Fatal(errchain.From(err).Error("crie format"))
}
},
}
Expand All @@ -58,7 +59,7 @@ var LsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
err := crieRun.Languages.Show(os.Stdout)
if err != nil {
log.Fatal(fmt.Errorf("crie list failed: %w", err))
log.Fatal(errchain.From(err).Error("crie list failed"))
}
},
}
Expand All @@ -73,7 +74,7 @@ var ChkCmd = &cobra.Command{
err := crieRun.Run(runner.LintTypeChk)

if err != nil {
log.Fatal(fmt.Errorf("crie check failed: %w", err))
log.Fatal(errchain.From(err).Error("crie check"))
}
},
}
Expand All @@ -89,7 +90,7 @@ Find the file extensions that dont have an associated regex match within crieRun
Run: func(cmd *cobra.Command, args []string) {
err := crieRun.NoStandards()
if err != nil {
log.Fatal(fmt.Errorf("finding unassociated files failed: %w", err))
log.Fatal(errchain.From(err).Error("finding unassociated files"))
}
},
}
Expand All @@ -102,15 +103,15 @@ var InitCmd = &cobra.Command{

RunE: func(_ *cobra.Command, _ []string) error {

err := language2.NewLanguageConfigFile(viper.GetString("Language.Conf"))
err := language.NewLanguageConfigFile(viper.GetString("Language.Conf"))
if err != nil {
return err
}
fmt.Printf("new language file created: %s\nused to overide crie internal language settings (optional / can be deleted)\n", viper.GetString("Language.Conf"))

fmt.Println()

var projectConfig project2.Config
var projectConfig project.Config
err = viper.Unmarshal(&projectConfig)
if err != nil {
return err
Expand All @@ -131,7 +132,7 @@ var ConfCmd = &cobra.Command{
Short: "Print configuration settings",
Long: "Print what crie has parsed from flags, env, the project file, and then defaults",
RunE: func(_ *cobra.Command, _ []string) error {
var projectConfig project2.Config
var projectConfig project.Config
err := viper.Unmarshal(&projectConfig)
if err != nil {
return err
Expand Down Expand Up @@ -161,7 +162,7 @@ var SchemaLangCmd = &cobra.Command{
Short: "Print the schema for language's configurations",
Long: `Print json schema for cries configuration format used override language project`,
Run: func(_ *cobra.Command, _ []string) {
schema := language2.Schema()
schema := language.Schema()
jsonBytes, err := json.MarshalIndent(schema, "", " ")
if err != nil {
return
Expand All @@ -177,7 +178,7 @@ var SchemaProjectCmd = &cobra.Command{
Short: "Print the schema for language's configurations",
Long: `Print json schema for cries configuration format used override language project`,
Run: func(_ *cobra.Command, _ []string) {
schema := project2.Schema()
schema := project.Schema()
jsonBytes, err := json.MarshalIndent(schema, "", " ")
if err != nil {
return
Expand All @@ -190,13 +191,7 @@ func stage(lintType runner.LintType) error {
log.Infof("❨ %s ❩", lintType.String())
err := crieRun.Run(lintType)
if err != nil {
if crieRun.Options.Continue {
// Log the error but allow subsequent stages to run.
log.Error(err)
return fmt.Errorf("crie %s failed: %w", lintType, err)
}
// In non-continue mode, fail immediately.
log.Fatal(fmt.Errorf("crie %s failed: %w", lintType, err))
return errchain.From(err).ErrorF("crie %s", lintType)
}
return nil
}
Expand All @@ -213,7 +208,11 @@ var LntCmd = &cobra.Command{

for _, lintType := range stages {
if err := stage(lintType); err != nil {
failedStages = append(failedStages, lintType.String())
if crieRun.Options.Continue {
failedStages = append(failedStages, lintType.String())
} else {
log.Fatal(err)
}
}
}

Expand Down
18 changes: 11 additions & 7 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package cli

import (
"fmt"
"sort"
"strings"

"github.com/tyhal/crie/internal/config/language"
"github.com/tyhal/crie/internal/config/project"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tyhal/crie/internal/config/language"
"github.com/tyhal/crie/internal/config/project"
"github.com/tyhal/crie/internal/errchain"
)

//`
Expand Down Expand Up @@ -59,6 +58,11 @@ format all python files

setLogging()

// enable git diff if target is set
if projectConfig.Lint.GitTarget != "" {
projectConfig.Lint.GitDiff = true
}

return nil
},
}
Expand Down Expand Up @@ -118,9 +122,9 @@ func addLintCommand(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVarP(&projectConfig.Lint.Passes, "passes", "p", false, "show files that passed")
errFatal(viper.BindPFlag("Lint.Passes", cmd.PersistentFlags().Lookup("passes")))

cmd.PersistentFlags().BoolVarP(&projectConfig.Lint.GitDiff, "git-diff", "g", false, "only use files from the current commit to (git-target)")
cmd.PersistentFlags().BoolVarP(&projectConfig.Lint.GitDiff, "git-diff", "g", false, "only check files changed in git")
errFatal(viper.BindPFlag("Lint.GitDiff", cmd.PersistentFlags().Lookup("git-diff")))
cmd.PersistentFlags().StringVarP(&projectConfig.Lint.GitTarget, "git-target", "t", "origin/main", "the branch to compare against to find changed files")
cmd.PersistentFlags().StringVarP(&projectConfig.Lint.GitTarget, "git-target", "t", "", "a target branch to compare against e.g 'remote/branch' or 'branch'")
errFatal(viper.BindPFlag("Lint.GitTarget", cmd.PersistentFlags().Lookup("git-target")))

cmd.PersistentFlags().StringVar(&projectConfig.Lint.Only, "only", "", "run with only one language (see `crie ls` for available options)")
Expand All @@ -139,7 +143,7 @@ func addCrieCommand(cmd *cobra.Command) {

func errFatal(err error) {
if err != nil {
log.Fatal(fmt.Errorf("incorrect viper configuration: %w", err))
log.Fatal(errchain.From(err).Error("incorrect viper configuration"))
}
}

Expand Down
8 changes: 4 additions & 4 deletions internal/config/language/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package language

import (
"bytes"
"fmt"
"os"

"github.com/tyhal/crie/internal/errchain"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -53,12 +53,12 @@ func LoadFile(path string) (*Languages, error) {

configData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read config file %s: %w", path, err)
return nil, errchain.From(err).ErrorF("readding config file %s", path)
}

var c Languages
if err := yaml.Unmarshal(configData, &c); err != nil {
return nil, fmt.Errorf("failed to parse config file %s: %w", path, err)
if err = yaml.Unmarshal(configData, &c); err != nil {
return nil, errchain.From(err).ErrorF("parsing config file %s", path)
}

merge(&defaultLanguageConfig, &c)
Expand Down
29 changes: 29 additions & 0 deletions internal/errchain/err.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Package errchain keeps consistency of displaying error messages with more context.
package errchain

import "fmt"

// ErrorChain wraps an error and provides helpers to add contextual messages
// while preserving the original error using Go's error wrapping.
type ErrorChain struct {
err error
}

// From creates a new ErrorChain rooted at the provided error so that
// additional context can be added in a consistent manner.
func From(err error) ErrorChain {
return ErrorChain{err: err}
}

// ErrorF formats a contextual message with the given format and arguments,
// and returns the original error wrapped with that context.
func (ec ErrorChain) ErrorF(format string, a ...any) error {
msg := fmt.Sprintf(format, a...)
return fmt.Errorf("%s ⟶ %w", msg, ec.err)
}

// Error adds a contextual message and returns the original error wrapped
// with that context.
func (ec ErrorChain) Error(msg string) error {
return fmt.Errorf("%s ⟶ %w", msg, ec.err)
}
49 changes: 49 additions & 0 deletions internal/errchain/err_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package errchain

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
)

func TestError_WrapsAndAddsContext(t *testing.T) {
base := errors.New("base failure")

err := From(base).Error("doing important work")

// It should wrap the base error
assert.ErrorIs(t, err, base)

// The message should contain our context and the base message
s := err.Error()
assert.Contains(t, s, "doing important work")
assert.Contains(t, s, base.Error())
}

func TestErrorF_WrapsAndFormats(t *testing.T) {
base := errors.New("not found")

err := From(base).ErrorF("fetching id %d", 42)

assert.ErrorIs(t, err, base)

s := err.Error()
assert.Contains(t, s, "fetching id 42")
assert.Contains(t, s, base.Error())
}

func TestChaining_PreservesOriginalAndAllContexts(t *testing.T) {
base := errors.New("disk full")

// First wrap
err1 := From(base).Error("writing cache")
// Second wrap by starting a new chain from the previous error
err2 := From(err1).ErrorF("attempt %d", 3)

assert.ErrorIs(t, err2, base)

s := err2.Error()
assert.Contains(t, s, "writing cache")
assert.Contains(t, s, "attempt 3")
}
4 changes: 2 additions & 2 deletions internal/runner/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package runner

import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
Expand All @@ -11,6 +10,7 @@ import (

"github.com/olekukonko/tablewriter"
log "github.com/sirupsen/logrus"
"github.com/tyhal/crie/internal/errchain"
"github.com/tyhal/crie/pkg/linter"
)

Expand Down Expand Up @@ -170,7 +170,7 @@ func (s *RunConfiguration) runLinters(lintType LintType, list []string) error {
func (s *RunConfiguration) Run(lintType LintType) error {
fileList, err := s.getFileList()
if err != nil {
return fmt.Errorf("failed to get filelist: %w", err)
return errchain.From(err).Error("getting filelist")
}
err = s.runLinters(lintType, fileList)
if err != nil {
Expand Down
Loading